You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mina.apache.org by Niklas Gustavsson <ni...@protocol7.com> on 2009/02/23 11:20:51 UTC

[FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Moving this to it's own thread.

On Mon, Feb 23, 2009 at 11:08 AM, Guillaume Nodet <gn...@gmail.com> wrote:
> FWIW, the test is hanging at the following point:

Looks another case of TCP/IP stacks behaving differently on different
platforms. Would you be able to see what state the server socket is in
when this happens (it runs on a random port so you have to look for
the process)?

> The timeout on the socket is set to 0, so I suspect it will just wait
> forever ...

Well, at least longer then anyone cares to wait around. I'll set a
shorter timeout for it.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Feb 27, 2009 at 2:06 PM, Ashish <pa...@gmail.com> wrote:
> Is OS name not sufficient for this? Agree that it leads to hard-coding.

HFS+ seems to be able to have different settings that affect the case
handling, thus looking at the OS name will not help. Also, you can
mount an ext3 file system on a Mac or a HFS+ file system on Linux.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Mar 6, 2009 at 8:30 PM, David Latorre <dv...@gmail.com> wrote:
> Do you know when it's likely that getCanonical*   fails? Should we try a
> workaround in that case? If you think our code is ok as is, that's much
> better!

I have no idea, which is why I choose to throw the exception. I'm also
okay with swallowing the exception and returning null like you did, if
we add a logging statement on WARN level.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by David Latorre <dv...@gmail.com>.
2009/3/6 Emmanuel Lecharny <el...@apache.org>

> Niklas Gustavsson wrote:
>
>> On Fri, Mar 6, 2009 at 11:57 AM, Emmanuel Lecharny <el...@apache.org>
>> wrote:
>>
>>
>>> Just a small remark : it would be _very_ cool if you can extend the
>>> NativeFtpFile interface with a getFile() method, because having to cast
>>> the
>>> object to get the so called PhysicalFile is a bit a PITA, IMHO :)
>>>
>>>
>>
>> Not sure I understand, NativeFtpFile is not an interface but an
>> implementation of the FtpFile interface. And you should pretty much
>> never need to get the underlying java.io.File object unless you really
>> know you're working with the native file system (FtpServer never makes
>> that assumption). And, since there are file system implementations
>> for, for example JDBC, there might not even be a file or even a
>> reasonable object we could return, at least not a java.io.File.
>>
>>
> Never mind. David's solution is way better. Yesturday, it was late, and it
> took me a bit of time to find the way to grab the File object, and I found
> the solution I proposed kind of dirty, to say the least. Doing the job in
> NativeFtpFile.equals() method is way cleaner.


Actually niklas had already commited the change himself when I sent the
email, the only difference being that he is not swallowing the Exception as
my quick code  - I sent the whole code just to remark that I didn't know
what to do with that exception.
Still I have some concerns about the getCanonicalFile/getCanonicalPath
methods because of that IOException. My thinking is that Sun is not using
getCanonical... in the File equals() method because it is not safe to rely
on it, otherwise, why would they provide a broken implementation of
FIle.equals()?

Do you know when it's likely that getCanonical*   fails? Should we try a
workaround in that case? If you think our code is ok as is, that's much
better!



> /niklas
>>
>>
>>
>
>
> --
> --
> cordialement, regards,
> Emmanuel Lécharny
> www.iktek.com
> directory.apache.org
>
>
>

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> On Fri, Mar 6, 2009 at 11:57 AM, Emmanuel Lecharny <el...@apache.org> wrote:
>   
>> Just a small remark : it would be _very_ cool if you can extend the
>> NativeFtpFile interface with a getFile() method, because having to cast the
>> object to get the so called PhysicalFile is a bit a PITA, IMHO :)
>>     
>
> Not sure I understand, NativeFtpFile is not an interface but an
> implementation of the FtpFile interface. And you should pretty much
> never need to get the underlying java.io.File object unless you really
> know you're working with the native file system (FtpServer never makes
> that assumption). And, since there are file system implementations
> for, for example JDBC, there might not even be a file or even a
> reasonable object we could return, at least not a java.io.File.
>   
Never mind. David's solution is way better. Yesturday, it was late, and 
it took me a bit of time to find the way to grab the File object, and I 
found the solution I proposed kind of dirty, to say the least. Doing the 
job in NativeFtpFile.equals() method is way cleaner.
> /niklas
>
>   


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Mar 6, 2009 at 11:57 AM, Emmanuel Lecharny <el...@apache.org> wrote:
> Just a small remark : it would be _very_ cool if you can extend the
> NativeFtpFile interface with a getFile() method, because having to cast the
> object to get the so called PhysicalFile is a bit a PITA, IMHO :)

Not sure I understand, NativeFtpFile is not an interface but an
implementation of the FtpFile interface. And you should pretty much
never need to get the underlying java.io.File object unless you really
know you're working with the native file system (FtpServer never makes
that assumption). And, since there are file system implementations
for, for example JDBC, there might not even be a file or even a
reasonable object we could return, at least not a java.io.File.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> I've moved the patch into NativeFtpFile where it belongs, and the test
> still pass on Linux. I've commited this to trunk (rev 750819),
> Emmanuel would you be able to rerun the test from trunk? If it passed,
> I will merge this into the 1.0.x branch as well.
>   
Will do.

Just a small remark : it would be _very_ cool if you can extend the 
NativeFtpFile interface with a getFile() method, because having to cast 
the object to get the so called PhysicalFile is a bit a PITA, IMHO :)


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Mar 6, 2009 at 12:56 AM, Emmanuel Lecharny <el...@apache.org> wrote:
> Ok, I have changed the RMDIR impl, and now, all the tests are passing.

This is great news!

> Could someone do the test on W$ and Linux ?

I've moved the patch into NativeFtpFile where it belongs, and the test
still pass on Linux. I've commited this to trunk (rev 750819),
Emmanuel would you be able to rerun the test from trunk? If it passed,
I will merge this into the 1.0.x branch as well.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Mar 6, 2009 at 12:04 PM, Emmanuel Lecharny <el...@apache.org> wrote:
> Apple, I know at least 8 persons who need a Mac Book Pro 17", 8 Gb, Quad
> core 3Ghz, 300 Gb SSD disk, 6h battery...

Yeah, send one my way :-D

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
David Latorre wrote:
> After changing NativeFtpFile equals to the followingcode :
>  @Override
>     public boolean equals(Object obj) {
>      try{
>      if(obj != null && obj instanceof NativeFtpFile) {
>      return this.file.getCanonicalPath().equals( ((NativeFtpFile)
> obj).file.getCanonicalPath() ) ;
>      }
>      }catch(IOException e){}
>      return false;
>     }
>
> All the tests are passing under Windows (Vista) with Jre 1.6.0_7 and  Jre
> 1.5.0_15
>   
Way better than the quick hack I submitted (but I did it around 1 am).

Funny how such a simple problem has stuck at least 8 high level 
developpers (!) for one full week... May be not having a Mac is also the 
reason we got stuck and also the lack of time for many of us...

Apple, I know at least 8 persons who need a Mac Book Pro 17", 8 Gb, Quad 
core 3Ghz, 300 Gb SSD disk, 6h battery...


And a special thank for Saï who finally found the way out of this maze !

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by David Latorre <dv...@gmail.com>.
2009/3/6 Emmanuel Lecharny <el...@apache.org>

> Sai Pullabhotla wrote:
>
>> That's what I was expecting. So, if the issue is about RMDIR on the
>> current
>> working directory, we should be able to match up the canonical paths and
>> if
>> they are same (the directory that was requested for deletion and the
>> current
>> working directory), send an error back. Does that sound correct?
>>
>>
> :)
>
> Ok, I have changed the RMDIR impl, and now, all the tests are passing.
> Following Sai's suggestion, here is what I have :
>
> instead of :
>
> if(file.equals(cwd)) { blah
>
> I now have :
>
> File cwdFile = ((NativeFtpFile)cwd).getPhysicalFile();
> File currentFile = ((NativeFtpFile)file).getPhysicalFile();
>
> if (cwdFile.getCanonicalPath().equals(currentFile.getCanonicalPath())) {
> blah
>
>
> and it works on mac.
>
> Could someone do the test on W$ and Linux ?
>

After changing NativeFtpFile equals to the followingcode :
 @Override
    public boolean equals(Object obj) {
     try{
     if(obj != null && obj instanceof NativeFtpFile) {
     return this.file.getCanonicalPath().equals( ((NativeFtpFile)
obj).file.getCanonicalPath() ) ;
     }
     }catch(IOException e){}
     return false;
    }

All the tests are passing under Windows (Vista) with Jre 1.6.0_7 and  Jre
1.5.0_15





>
> Thanks for the heads up, Sai !
>
> --
> --
> cordialement, regards,
> Emmanuel Lécharny
> www.iktek.com
> directory.apache.org
>
>
>

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Sai Pullabhotla wrote:
> That's what I was expecting. So, if the issue is about RMDIR on the current
> working directory, we should be able to match up the canonical paths and if
> they are same (the directory that was requested for deletion and the current
> working directory), send an error back. Does that sound correct?
>   
:)

Ok, I have changed the RMDIR impl, and now, all the tests are passing. 
Following Sai's suggestion, here is what I have :

instead of :

if(file.equals(cwd)) { blah

I now have :

File cwdFile = ((NativeFtpFile)cwd).getPhysicalFile();
File currentFile = ((NativeFtpFile)file).getPhysicalFile();

if (cwdFile.getCanonicalPath().equals(currentFile.getCanonicalPath())) { 
blah


and it works on mac.

Could someone do the test on W$ and Linux ?

Thanks for the heads up, Sai !

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Sai Pullabhotla <sa...@jmethods.com>.
That's what I was expecting. So, if the issue is about RMDIR on the current
working directory, we should be able to match up the canonical paths and if
they are same (the directory that was requested for deletion and the current
working directory), send an error back. Does that sound correct?

Sai Pullabhotla
Phone: (402) 408-5753
Fax: (402) 408-6861
www.jMethods.com



On Thu, Mar 5, 2009 at 3:38 PM, Emmanuel Lecharny <el...@apache.org>wrote:

> Niklas Gustavsson wrote:
>
>> On Thu, Mar 5, 2009 at 8:55 PM, Emmanuel Lecharny <el...@apache.org>
>> wrote:
>>
>>
>>> i'm pretty sure I tested it, and the getCanonicalPath() keeps the name
>>> which
>>> as been used on HSF+.
>>>
>>>
>>
>> Could you please clarify that? If a file exists with the name "foo",
>> and we call new File("FOO").getCanonicalPath(), what casing will it
>> return?
>>
>>
>
> new File("FOO").getCanonicalPath() --> foo if the foo file exists.
> new File("FOO").getCanonicalPath() --> FOO if the foo file does not exist.
>
> In other words, it returns the existing name, or the new name.
>
>
>>
>
>  /niklas
>>
>>
>>
>
>
> --
> --
> cordialement, regards,
> Emmanuel Lécharny
> www.iktek.com
> directory.apache.org
>
>
>

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> On Thu, Mar 5, 2009 at 8:55 PM, Emmanuel Lecharny <el...@apache.org> wrote:
>   
>> i'm pretty sure I tested it, and the getCanonicalPath() keeps the name which
>> as been used on HSF+.
>>     
>
> Could you please clarify that? If a file exists with the name "foo",
> and we call new File("FOO").getCanonicalPath(), what casing will it
> return?
>   

new File("FOO").getCanonicalPath() --> foo if the foo file exists.
new File("FOO").getCanonicalPath() --> FOO if the foo file does not exist.

In other words, it returns the existing name, or the new name.
>   

> /niklas
>
>   


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Thu, Mar 5, 2009 at 8:55 PM, Emmanuel Lecharny <el...@apache.org> wrote:
> i'm pretty sure I tested it, and the getCanonicalPath() keeps the name which
> as been used on HSF+.

Could you please clarify that? If a file exists with the name "foo",
and we call new File("FOO").getCanonicalPath(), what casing will it
return?

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> On Thu, Mar 5, 2009 at 5:34 PM, Sai Pullabhotla
> <sa...@jmethods.com> wrote:
>   
>> I would like to take this one step back as I think that the
>> getCanonicalFile() or getCanonicalPath() on an existing file should return
>> the exact file name with the correct case as it is stored on the file
>> system. At least that is what the JavaDoc says.
>>     
>
> There was some discussion previously on this thread where I believe
> Emmanuel tested canonical paths with no success. But, let's hope I got
> it wrong :-)
>   
i'm pretty sure I tested it, and the getCanonicalPath() keeps the name 
which as been used on HSF+.
> /niklas
>
>   


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Thu, Mar 5, 2009 at 5:34 PM, Sai Pullabhotla
<sa...@jmethods.com> wrote:
> I would like to take this one step back as I think that the
> getCanonicalFile() or getCanonicalPath() on an existing file should return
> the exact file name with the correct case as it is stored on the file
> system. At least that is what the JavaDoc says.

There was some discussion previously on this thread where I believe
Emmanuel tested canonical paths with no success. But, let's hope I got
it wrong :-)

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Sai Pullabhotla <sa...@jmethods.com>.
I would like to take this one step back as I think that the
getCanonicalFile() or getCanonicalPath() on an existing file should return
the exact file name with the correct case as it is stored on the file
system. At least that is what the JavaDoc says.

Can some one run this test program on OS X/HFS and post the results back?
Before running this, make sure there is no directory named "Foo" in your
working directory.

import java.io.File;
import java.io.IOException;

public class FileCaseTest {

    public static void main(String[] args) throws IOException {
        File dir = new File("Foo");
        boolean created = dir.mkdir();
        System.out.println("Created directory " + dir + ": " + created);

        dir = new File("FOO");
        System.out.println("Absolute Path: " + dir.getAbsoluteFile());
        System.out.println("Canonical Path: " + dir.getCanonicalFile());
    }
}

This is what I get on Windows:

Created directory Foo: true
Absolute Path: D:\linomasoftware\projects\test\FOO
Canonical Path: D:\linomasoftware\projects\test\Foo

On Linux:

Created directory Foo: true
Absolute Path: /home/inspiron/dev/eclipseworkspace/develop/FOO
Canonical Path: /home/inspiron/dev/eclipseworkspace/develop/FOO

The canonical path is still in all CAPS because there is no file with the
name FOO exists. I would be curious to see what results we get back with the
HFS file system in question.

Regards,

Sai Pullabhotla
Phone: (402) 408-5753
Fax: (402) 408-6861
www.jMethods.com



On Wed, Mar 4, 2009 at 4:13 PM, Niklas Gustavsson <ni...@protocol7.com>wrote:

> On Mon, Mar 2, 2009 at 4:54 PM, Niklas Gustavsson <ni...@protocol7.com>
> wrote:
> > Let me whip up a prototype and we can test it on the available platforms.
>
> Alright, here's a prototype that I would much appreciate if all of you
> would take the time to test. First of all, you need to set the
> FILE_SYSTEM_TYPE to the correct value (this is only used for
> verification in the tests). On case sensitive file systems (most of
> the *nix file systems), this should be set to
> FileSystemType.CaseSensitive. On NTFS it should be set to
> CaseInsensitiveMissingAsTrue, and on case-insensitive HFS to
> CaseInsensitiveMissingAsFalse. It would be very interesting to have
> this code tested on other file systems. If you do, please report the
> file system and the test results.
>
> /niklas
>
> package org.apache.ftpserver.filesystem.nativefs.impl;
>
> import java.io.File;
> import java.io.FilenameFilter;
> import java.io.IOException;
>
> import junit.framework.TestCase;
>
> public class FileEqualsTest extends TestCase {
>
>    private enum FileSystemType {
>        CaseSensitive,
>        // non-existing files with different casing are equal
>        // e.g. NTFS
>        CaseInsensitiveMissingAsTrue,
>        // non-existing files with different casing are non-equal
>        // e.g. HFS
>        CaseInsensitiveMissingAsFalse
>    };
>
>    private static final FileSystemType FILE_SYSTEM_TYPE =
> FileSystemType.CaseSensitive;
>
>    private boolean isCaseSensitive() {
>        return FILE_SYSTEM_TYPE == FileSystemType.CaseSensitive;
>    }
>
>    private boolean isCaseInsensitive() {
>        return FILE_SYSTEM_TYPE != FileSystemType.CaseSensitive;
>    }
>
>    @Override
>    protected void setUp() throws Exception {
>        System.out.println("File system type: " + FILE_SYSTEM_TYPE);
>        super.setUp();
>    }
>
>    public void testSimple() throws IOException {
>        File f1 = new File("foo");
>        assertTrue(f1.createNewFile());
>        File f2 = new File("foo");
>
>        assertTrue(equals(f1, f2));
>    }
>
>    public void testNonExistingButSimple() {
>        File f1 = new File("foo");
>        File f2 = new File("foo");
>
>        assertTrue(equals(f1, f2));
>    }
>
>    public void testDifferentCase() throws IOException {
>        File f1 = new File("foo");
>        assertTrue(f1.createNewFile());
>        File f2 = new File("FOO");
>
>        // if this succeeds, we have two different files
>        assertEquals(isCaseSensitive(), f2.createNewFile());
>
>        assertEquals(isCaseInsensitive(), equals(f1, f2));
>    }
>
>    public void testDifferentCaseNonExisting() throws IOException {
>        File f1 = new File("foo");
>        File f2 = new File("FOO");
>
>        assertEquals(FILE_SYSTEM_TYPE ==
> FileSystemType.CaseInsensitiveMissingAsTrue, equals(f1, f2));
>    }
>
>    public void testSameNameDifferentParent() throws IOException {
>        File f1 = new File("foo");
>        assertTrue(f1.createNewFile());
>        File dir2 = new File("dir");
>        assertTrue(dir2.mkdir());
>        File f2 = new File(dir2, "foo");
>        assertTrue(f2.createNewFile());
>
>        assertFalse(equals(f1, f2));
>    }
>
>    public boolean equals(final File f1, final File f2) {
>        if (f1 == null || f2 == null) {
>            return false;
>        }
>
>        if (f1.equals(f2)) {
>            // file equals, valid on all file systems
>            return true;
>        } else {
>            boolean f1Exists = f1.exists();
>            boolean f2Exists = f2.exists();
>
>            if (f1.getName().equalsIgnoreCase(f2.getName())) {
>                // same name, do both exist?
>                if (f1Exists && f2Exists) {
>                    // both files exists, do they have the same parent?
>
>                    // TODO should we use canonical or absolute path?
>                    File f1Parent = f1.getAbsoluteFile().getParentFile();
>                    File f2Parent = f2.getAbsoluteFile().getParentFile();
>
>                    if (f1Parent != null && f2Parent != null) {
>                        if (equals(f1Parent, f2Parent)) {
>                            // okay, if we got here, the parents are the
> same,
>                            // the file names are the same and both files
> exists
>                            // let's check if there are multiple files
> or only one in the parent
>                            // with that name
>
>
>                            // choosing either parent should be fine,
> they are equal
>                            String[] files = f1Parent
>                                    .list(new FilenameFilter() {
>                                        public boolean accept(File
> dir, String name) {
>                                            return name.equalsIgnoreCase(f1
>                                                    .getName());
>                                        }
>                                    });
>
>                            if (files.length == 1) {
>                                // exactly one file matched the name,
> the files must be equal
>                                return true;
>                            } else if (files.length > 1) {
>                                return false;
>                            } else {
>                                // no file matching, must be a bug somewhere
>                                throw new RuntimeException("Should not
> happen");
>                            }
>                        } else {
>                            // different parents, return false
>                            return false;
>                        }
>                    } else if (f1Parent == null && f2Parent == null) {
>                        // no parents, we can do nothing more and thus
> have to return false
>                        return false;
>                    } else {
>                        // different parents
>                        return false;
>                    }
>                } else if (!f1Exists && !f2Exists) {
>                    // none of the file exists, we can only trust the
> equals result (which by now must be false)
>                    return false;
>                } else {
>                    // only one of the files exists, return false
>                    return false;
>                }
>            } else {
>                // file names not equal
>                return false;
>            }
>        }
>    }
>
>    @Override
>    protected void tearDown() throws Exception {
>        new File("foo").delete();
>        new File("FOO").delete();
>        new File("dir/foo").delete();
>        new File("dir").delete();
>    }
>
> }
>

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Maarten Bosteels <mb...@gmail.com>.
Works fine on Fedora 10, ext2, ext3 and ntfs mounted with ntfs-3g (fuseblk)
For the mounted ntfs partition I had to use CaseSensitive.

Maarten

On Thu, Mar 5, 2009 at 10:39 AM, Emmanuel Lecharny <el...@apache.org>wrote:

> Works fine on my Mac OS X 10.4/Java 5
>
> On Wed, Mar 4, 2009 at 11:13 PM, Niklas Gustavsson <ni...@protocol7.com>
> wrote:
> > On Mon, Mar 2, 2009 at 4:54 PM, Niklas Gustavsson <ni...@protocol7.com>
> wrote:
> >> Let me whip up a prototype and we can test it on the available
> platforms.
> >
> > Alright, here's a prototype that I would much appreciate if all of you
> > would take the time to test. First of all, you need to set the
> > FILE_SYSTEM_TYPE to the correct value (this is only used for
> > verification in the tests). On case sensitive file systems (most of
> > the *nix file systems), this should be set to
> > FileSystemType.CaseSensitive. On NTFS it should be set to
> > CaseInsensitiveMissingAsTrue, and on case-insensitive HFS to
> > CaseInsensitiveMissingAsFalse. It would be very interesting to have
> > this code tested on other file systems. If you do, please report the
> > file system and the test results.
> >
> > /niklas
> >
> > package org.apache.ftpserver.filesystem.nativefs.impl;
> >
> > import java.io.File;
> > import java.io.FilenameFilter;
> > import java.io.IOException;
> >
> > import junit.framework.TestCase;
> >
> > public class FileEqualsTest extends TestCase {
> >
> >    private enum FileSystemType {
> >        CaseSensitive,
> >        // non-existing files with different casing are equal
> >        // e.g. NTFS
> >        CaseInsensitiveMissingAsTrue,
> >        // non-existing files with different casing are non-equal
> >        // e.g. HFS
> >        CaseInsensitiveMissingAsFalse
> >    };
> >
> >    private static final FileSystemType FILE_SYSTEM_TYPE =
> > FileSystemType.CaseSensitive;
> >
> >    private boolean isCaseSensitive() {
> >        return FILE_SYSTEM_TYPE == FileSystemType.CaseSensitive;
> >    }
> >
> >    private boolean isCaseInsensitive() {
> >        return FILE_SYSTEM_TYPE != FileSystemType.CaseSensitive;
> >    }
> >
> >    @Override
> >    protected void setUp() throws Exception {
> >        System.out.println("File system type: " + FILE_SYSTEM_TYPE);
> >        super.setUp();
> >    }
> >
> >    public void testSimple() throws IOException {
> >        File f1 = new File("foo");
> >        assertTrue(f1.createNewFile());
> >        File f2 = new File("foo");
> >
> >        assertTrue(equals(f1, f2));
> >    }
> >
> >    public void testNonExistingButSimple() {
> >        File f1 = new File("foo");
> >        File f2 = new File("foo");
> >
> >        assertTrue(equals(f1, f2));
> >    }
> >
> >    public void testDifferentCase() throws IOException {
> >        File f1 = new File("foo");
> >        assertTrue(f1.createNewFile());
> >        File f2 = new File("FOO");
> >
> >        // if this succeeds, we have two different files
> >        assertEquals(isCaseSensitive(), f2.createNewFile());
> >
> >        assertEquals(isCaseInsensitive(), equals(f1, f2));
> >    }
> >
> >    public void testDifferentCaseNonExisting() throws IOException {
> >        File f1 = new File("foo");
> >        File f2 = new File("FOO");
> >
> >        assertEquals(FILE_SYSTEM_TYPE ==
> > FileSystemType.CaseInsensitiveMissingAsTrue, equals(f1, f2));
> >    }
> >
> >    public void testSameNameDifferentParent() throws IOException {
> >        File f1 = new File("foo");
> >        assertTrue(f1.createNewFile());
> >        File dir2 = new File("dir");
> >        assertTrue(dir2.mkdir());
> >        File f2 = new File(dir2, "foo");
> >        assertTrue(f2.createNewFile());
> >
> >        assertFalse(equals(f1, f2));
> >    }
> >
> >    public boolean equals(final File f1, final File f2) {
> >        if (f1 == null || f2 == null) {
> >            return false;
> >        }
> >
> >        if (f1.equals(f2)) {
> >            // file equals, valid on all file systems
> >            return true;
> >        } else {
> >            boolean f1Exists = f1.exists();
> >            boolean f2Exists = f2.exists();
> >
> >            if (f1.getName().equalsIgnoreCase(f2.getName())) {
> >                // same name, do both exist?
> >                if (f1Exists && f2Exists) {
> >                    // both files exists, do they have the same parent?
> >
> >                    // TODO should we use canonical or absolute path?
> >                    File f1Parent = f1.getAbsoluteFile().getParentFile();
> >                    File f2Parent = f2.getAbsoluteFile().getParentFile();
> >
> >                    if (f1Parent != null && f2Parent != null) {
> >                        if (equals(f1Parent, f2Parent)) {
> >                            // okay, if we got here, the parents are the
> same,
> >                            // the file names are the same and both files
> exists
> >                            // let's check if there are multiple files
> > or only one in the parent
> >                            // with that name
> >
> >
> >                            // choosing either parent should be fine,
> > they are equal
> >                            String[] files = f1Parent
> >                                    .list(new FilenameFilter() {
> >                                        public boolean accept(File
> > dir, String name) {
> >                                            return
> name.equalsIgnoreCase(f1
> >                                                    .getName());
> >                                        }
> >                                    });
> >
> >                            if (files.length == 1) {
> >                                // exactly one file matched the name,
> > the files must be equal
> >                                return true;
> >                            } else if (files.length > 1) {
> >                                return false;
> >                            } else {
> >                                // no file matching, must be a bug
> somewhere
> >                                throw new RuntimeException("Should not
> happen");
> >                            }
> >                        } else {
> >                            // different parents, return false
> >                            return false;
> >                        }
> >                    } else if (f1Parent == null && f2Parent == null) {
> >                        // no parents, we can do nothing more and thus
> > have to return false
> >                        return false;
> >                    } else {
> >                        // different parents
> >                        return false;
> >                    }
> >                } else if (!f1Exists && !f2Exists) {
> >                    // none of the file exists, we can only trust the
> > equals result (which by now must be false)
> >                    return false;
> >                } else {
> >                    // only one of the files exists, return false
> >                    return false;
> >                }
> >            } else {
> >                // file names not equal
> >                return false;
> >            }
> >        }
> >    }
> >
> >    @Override
> >    protected void tearDown() throws Exception {
> >        new File("foo").delete();
> >        new File("FOO").delete();
> >        new File("dir/foo").delete();
> >        new File("dir").delete();
> >    }
> >
> > }
> >
>
>
>
> --
> Regards,
> Cordialement,
> Emmanuel Lécharny
> www.iktek.com
>

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Works fine on my Mac OS X 10.4/Java 5

On Wed, Mar 4, 2009 at 11:13 PM, Niklas Gustavsson <ni...@protocol7.com> wrote:
> On Mon, Mar 2, 2009 at 4:54 PM, Niklas Gustavsson <ni...@protocol7.com> wrote:
>> Let me whip up a prototype and we can test it on the available platforms.
>
> Alright, here's a prototype that I would much appreciate if all of you
> would take the time to test. First of all, you need to set the
> FILE_SYSTEM_TYPE to the correct value (this is only used for
> verification in the tests). On case sensitive file systems (most of
> the *nix file systems), this should be set to
> FileSystemType.CaseSensitive. On NTFS it should be set to
> CaseInsensitiveMissingAsTrue, and on case-insensitive HFS to
> CaseInsensitiveMissingAsFalse. It would be very interesting to have
> this code tested on other file systems. If you do, please report the
> file system and the test results.
>
> /niklas
>
> package org.apache.ftpserver.filesystem.nativefs.impl;
>
> import java.io.File;
> import java.io.FilenameFilter;
> import java.io.IOException;
>
> import junit.framework.TestCase;
>
> public class FileEqualsTest extends TestCase {
>
>    private enum FileSystemType {
>        CaseSensitive,
>        // non-existing files with different casing are equal
>        // e.g. NTFS
>        CaseInsensitiveMissingAsTrue,
>        // non-existing files with different casing are non-equal
>        // e.g. HFS
>        CaseInsensitiveMissingAsFalse
>    };
>
>    private static final FileSystemType FILE_SYSTEM_TYPE =
> FileSystemType.CaseSensitive;
>
>    private boolean isCaseSensitive() {
>        return FILE_SYSTEM_TYPE == FileSystemType.CaseSensitive;
>    }
>
>    private boolean isCaseInsensitive() {
>        return FILE_SYSTEM_TYPE != FileSystemType.CaseSensitive;
>    }
>
>    @Override
>    protected void setUp() throws Exception {
>        System.out.println("File system type: " + FILE_SYSTEM_TYPE);
>        super.setUp();
>    }
>
>    public void testSimple() throws IOException {
>        File f1 = new File("foo");
>        assertTrue(f1.createNewFile());
>        File f2 = new File("foo");
>
>        assertTrue(equals(f1, f2));
>    }
>
>    public void testNonExistingButSimple() {
>        File f1 = new File("foo");
>        File f2 = new File("foo");
>
>        assertTrue(equals(f1, f2));
>    }
>
>    public void testDifferentCase() throws IOException {
>        File f1 = new File("foo");
>        assertTrue(f1.createNewFile());
>        File f2 = new File("FOO");
>
>        // if this succeeds, we have two different files
>        assertEquals(isCaseSensitive(), f2.createNewFile());
>
>        assertEquals(isCaseInsensitive(), equals(f1, f2));
>    }
>
>    public void testDifferentCaseNonExisting() throws IOException {
>        File f1 = new File("foo");
>        File f2 = new File("FOO");
>
>        assertEquals(FILE_SYSTEM_TYPE ==
> FileSystemType.CaseInsensitiveMissingAsTrue, equals(f1, f2));
>    }
>
>    public void testSameNameDifferentParent() throws IOException {
>        File f1 = new File("foo");
>        assertTrue(f1.createNewFile());
>        File dir2 = new File("dir");
>        assertTrue(dir2.mkdir());
>        File f2 = new File(dir2, "foo");
>        assertTrue(f2.createNewFile());
>
>        assertFalse(equals(f1, f2));
>    }
>
>    public boolean equals(final File f1, final File f2) {
>        if (f1 == null || f2 == null) {
>            return false;
>        }
>
>        if (f1.equals(f2)) {
>            // file equals, valid on all file systems
>            return true;
>        } else {
>            boolean f1Exists = f1.exists();
>            boolean f2Exists = f2.exists();
>
>            if (f1.getName().equalsIgnoreCase(f2.getName())) {
>                // same name, do both exist?
>                if (f1Exists && f2Exists) {
>                    // both files exists, do they have the same parent?
>
>                    // TODO should we use canonical or absolute path?
>                    File f1Parent = f1.getAbsoluteFile().getParentFile();
>                    File f2Parent = f2.getAbsoluteFile().getParentFile();
>
>                    if (f1Parent != null && f2Parent != null) {
>                        if (equals(f1Parent, f2Parent)) {
>                            // okay, if we got here, the parents are the same,
>                            // the file names are the same and both files exists
>                            // let's check if there are multiple files
> or only one in the parent
>                            // with that name
>
>
>                            // choosing either parent should be fine,
> they are equal
>                            String[] files = f1Parent
>                                    .list(new FilenameFilter() {
>                                        public boolean accept(File
> dir, String name) {
>                                            return name.equalsIgnoreCase(f1
>                                                    .getName());
>                                        }
>                                    });
>
>                            if (files.length == 1) {
>                                // exactly one file matched the name,
> the files must be equal
>                                return true;
>                            } else if (files.length > 1) {
>                                return false;
>                            } else {
>                                // no file matching, must be a bug somewhere
>                                throw new RuntimeException("Should not happen");
>                            }
>                        } else {
>                            // different parents, return false
>                            return false;
>                        }
>                    } else if (f1Parent == null && f2Parent == null) {
>                        // no parents, we can do nothing more and thus
> have to return false
>                        return false;
>                    } else {
>                        // different parents
>                        return false;
>                    }
>                } else if (!f1Exists && !f2Exists) {
>                    // none of the file exists, we can only trust the
> equals result (which by now must be false)
>                    return false;
>                } else {
>                    // only one of the files exists, return false
>                    return false;
>                }
>            } else {
>                // file names not equal
>                return false;
>            }
>        }
>    }
>
>    @Override
>    protected void tearDown() throws Exception {
>        new File("foo").delete();
>        new File("FOO").delete();
>        new File("dir/foo").delete();
>        new File("dir").delete();
>    }
>
> }
>



-- 
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Mar 2, 2009 at 4:54 PM, Niklas Gustavsson <ni...@protocol7.com> wrote:
> Let me whip up a prototype and we can test it on the available platforms.

Alright, here's a prototype that I would much appreciate if all of you
would take the time to test. First of all, you need to set the
FILE_SYSTEM_TYPE to the correct value (this is only used for
verification in the tests). On case sensitive file systems (most of
the *nix file systems), this should be set to
FileSystemType.CaseSensitive. On NTFS it should be set to
CaseInsensitiveMissingAsTrue, and on case-insensitive HFS to
CaseInsensitiveMissingAsFalse. It would be very interesting to have
this code tested on other file systems. If you do, please report the
file system and the test results.

/niklas

package org.apache.ftpserver.filesystem.nativefs.impl;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;

import junit.framework.TestCase;

public class FileEqualsTest extends TestCase {

    private enum FileSystemType {
        CaseSensitive,
        // non-existing files with different casing are equal
        // e.g. NTFS
        CaseInsensitiveMissingAsTrue,
        // non-existing files with different casing are non-equal
        // e.g. HFS
        CaseInsensitiveMissingAsFalse
    };

    private static final FileSystemType FILE_SYSTEM_TYPE =
FileSystemType.CaseSensitive;

    private boolean isCaseSensitive() {
        return FILE_SYSTEM_TYPE == FileSystemType.CaseSensitive;
    }

    private boolean isCaseInsensitive() {
        return FILE_SYSTEM_TYPE != FileSystemType.CaseSensitive;
    }

    @Override
    protected void setUp() throws Exception {
        System.out.println("File system type: " + FILE_SYSTEM_TYPE);
        super.setUp();
    }

    public void testSimple() throws IOException {
        File f1 = new File("foo");
        assertTrue(f1.createNewFile());
        File f2 = new File("foo");

        assertTrue(equals(f1, f2));
    }

    public void testNonExistingButSimple() {
        File f1 = new File("foo");
        File f2 = new File("foo");

        assertTrue(equals(f1, f2));
    }

    public void testDifferentCase() throws IOException {
        File f1 = new File("foo");
        assertTrue(f1.createNewFile());
        File f2 = new File("FOO");

        // if this succeeds, we have two different files
        assertEquals(isCaseSensitive(), f2.createNewFile());

        assertEquals(isCaseInsensitive(), equals(f1, f2));
    }

    public void testDifferentCaseNonExisting() throws IOException {
        File f1 = new File("foo");
        File f2 = new File("FOO");

        assertEquals(FILE_SYSTEM_TYPE ==
FileSystemType.CaseInsensitiveMissingAsTrue, equals(f1, f2));
    }

    public void testSameNameDifferentParent() throws IOException {
        File f1 = new File("foo");
        assertTrue(f1.createNewFile());
        File dir2 = new File("dir");
        assertTrue(dir2.mkdir());
        File f2 = new File(dir2, "foo");
        assertTrue(f2.createNewFile());

        assertFalse(equals(f1, f2));
    }

    public boolean equals(final File f1, final File f2) {
        if (f1 == null || f2 == null) {
            return false;
        }

        if (f1.equals(f2)) {
            // file equals, valid on all file systems
            return true;
        } else {
            boolean f1Exists = f1.exists();
            boolean f2Exists = f2.exists();

            if (f1.getName().equalsIgnoreCase(f2.getName())) {
                // same name, do both exist?
                if (f1Exists && f2Exists) {
                    // both files exists, do they have the same parent?

                    // TODO should we use canonical or absolute path?
                    File f1Parent = f1.getAbsoluteFile().getParentFile();
                    File f2Parent = f2.getAbsoluteFile().getParentFile();

                    if (f1Parent != null && f2Parent != null) {
                        if (equals(f1Parent, f2Parent)) {
                            // okay, if we got here, the parents are the same,
                            // the file names are the same and both files exists
                            // let's check if there are multiple files
or only one in the parent
                            // with that name


                            // choosing either parent should be fine,
they are equal
                            String[] files = f1Parent
                                    .list(new FilenameFilter() {
                                        public boolean accept(File
dir, String name) {
                                            return name.equalsIgnoreCase(f1
                                                    .getName());
                                        }
                                    });

                            if (files.length == 1) {
                                // exactly one file matched the name,
the files must be equal
                                return true;
                            } else if (files.length > 1) {
                                return false;
                            } else {
                                // no file matching, must be a bug somewhere
                                throw new RuntimeException("Should not happen");
                            }
                        } else {
                            // different parents, return false
                            return false;
                        }
                    } else if (f1Parent == null && f2Parent == null) {
                        // no parents, we can do nothing more and thus
have to return false
                        return false;
                    } else {
                        // different parents
                        return false;
                    }
                } else if (!f1Exists && !f2Exists) {
                    // none of the file exists, we can only trust the
equals result (which by now must be false)
                    return false;
                } else {
                    // only one of the files exists, return false
                    return false;
                }
            } else {
                // file names not equal
                return false;
            }
        }
    }

    @Override
    protected void tearDown() throws Exception {
        new File("foo").delete();
        new File("FOO").delete();
        new File("dir/foo").delete();
        new File("dir").delete();
    }

}

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Mar 2, 2009 at 8:02 PM, Maarten Bosteels
<mb...@gmail.com> wrote:
> Would it be a viable option to let users of FtpServer define which
> mount-points use a case-insensitive file-system ?
> I mean an out-of-the-box FtpServer config that works for 95% of the
> user-base and the other 5% would have to do some extra configuration.

Yes, I think that would be the fallback if we fail to find a good
enough code for doing this.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Maarten Bosteels <mb...@gmail.com>.
Would it be a viable option to let users of FtpServer define which
mount-points use a case-insensitive file-system ?
I mean an out-of-the-box FtpServer config that works for 95% of the
user-base and the other 5% would have to do some extra configuration.

Maarten


On Mon, Mar 2, 2009 at 6:12 PM, Niklas Gustavsson <ni...@protocol7.com>wrote:

> On Mon, Mar 2, 2009 at 6:01 PM, Sai Pullabhotla
> <sa...@jmethods.com> wrote:
> > Does this help at all?
> >
> > http://lists.apple.com/archives/java-dev/2004/Feb/msg00331.html
>
> I've posted this previously in this thread, however they do not seem
> to reach any conclusion beyond this being more complex that you might
> think :-)
>
> /niklas
>

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Mar 2, 2009 at 6:01 PM, Sai Pullabhotla
<sa...@jmethods.com> wrote:
> Does this help at all?
>
> http://lists.apple.com/archives/java-dev/2004/Feb/msg00331.html

I've posted this previously in this thread, however they do not seem
to reach any conclusion beyond this being more complex that you might
think :-)

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Sai Pullabhotla <sa...@jmethods.com>.
Does this help at all?

http://lists.apple.com/archives/java-dev/2004/Feb/msg00331.html

Sai Pullabhotla
Phone: (402) 408-5753
Fax: (402) 408-6861
www.jMethods.com



On Mon, Mar 2, 2009 at 9:54 AM, Niklas Gustavsson <ni...@protocol7.com>wrote:

> On Mon, Mar 2, 2009 at 1:17 PM, Emmanuel Lecharny <el...@apache.org>
> wrote:
> > It may be just a matter of checking that the file can be deleted, then
> check
> > that the working directory still exists after having done the deletion.
> If
> > so, we are golden, otherwise, we have to recreate it, and send an error.
>
> Recreating it will cause several side effects (might change ownership,
> permissions, inode).
>
> > In case the working directory is not empty, the deletion will fail
> anyway.
> >
> > if we don't want to delete the working directory for some reason, we can
> > rename it.
>
> Not convinced this is a very good anyways. As mentioned previously,
> FTP server file systems are commonly monitored for file changes,
> concurrent users might access the same directory and so on. I would
> prefer that we either do or do not do an action, rather than doing it
> in several steps.
>
> Let me whip up a prototype and we can test it on the available platforms.
>
> /niklas
>

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Mar 2, 2009 at 1:17 PM, Emmanuel Lecharny <el...@apache.org> wrote:
> It may be just a matter of checking that the file can be deleted, then check
> that the working directory still exists after having done the deletion. If
> so, we are golden, otherwise, we have to recreate it, and send an error.

Recreating it will cause several side effects (might change ownership,
permissions, inode).

> In case the working directory is not empty, the deletion will fail anyway.
>
> if we don't want to delete the working directory for some reason, we can
> rename it.

Not convinced this is a very good anyways. As mentioned previously,
FTP server file systems are commonly monitored for file changes,
concurrent users might access the same directory and so on. I would
prefer that we either do or do not do an action, rather than doing it
in several steps.

Let me whip up a prototype and we can test it on the available platforms.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
What about taking the problem from the other side ?

The test fails because :
- we are trying to delete the current working directory
- doing a
FtpFile cwd = session.getFileSystemView().getWorkingDirectory();
        if(file.equals(cwd)) {
does not work on Mac OS X and Java 6 because the file handler are 
considered as different, just because their name are not the same
- but the deletion works because behind the curtain, Mac OS X can delete 
the file, without taking care of the case sentivity.

It may be just a matter of checking that the file can be deleted, then 
check that the working directory still exists after having done the 
deletion. If so, we are golden, otherwise, we have to recreate it, and 
send an error.

In case the working directory is not empty, the deletion will fail anyway.

if we don't want to delete the working directory for some reason, we can 
rename it.

That should do the trick, IMO.

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Ashish <pa...@gmail.com>.
On Mon, Mar 2, 2009 at 4:34 PM, Niklas Gustavsson <ni...@protocol7.com> wrote:
> On Mon, Mar 2, 2009 at 11:52 AM, Ashish <pa...@gmail.com> wrote:
>> Can't we create the name like File file = new
>> File("FiLe"+System.currentTimeMillis());
>> check if it exists. Chance are very rare that it will.
>>
>> If it exist recreate a new file name.
>> If it doesn't exist, we call file.createNewFile(); and do the case
>> sensitive stuff.
>
> Problem is, we might be running on a read-only file system. Or, as
> common with FTP servers, file systems that is being monitored by other
> applications (over FTP or locally).

Can't we ship two weirdly name files with our distribution and test
for equality on them :-)
Or how about providing a default behavior(like we discussed) and
provide a hook for customizing the same.


>>> Would that work? Step 4 would mean taking a performance penalty if
>>> there are lots of files in the parent directory, but it should not be
>>> a very common case.
>>
>> I hope, we would be doing this once, to establish if File System is
>> case sensitive or not.
>> So performance shouldn't really be a big cause.
>
> Problem is, we don't know where file systems (as in the *nix sense)
> change as you can mount or link file systems together where ever. So,
> we pretty much have to do this on every equals... currently we don't
> use equals so much so it would probably be okay, but the Javadoc must
> come with a huge warning post if we decide to go with any of these
> ideas for checking file equivalence.

Yeah I got it :) May be I should take a break

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Ashish <pa...@gmail.com>.
>
> File f1 = new File( "test" );
> File f2 = new File( "TEST" );
>
> if ( !f1.equals( f2 ) ) {
>   if ( f1.createNewFile() != f2.createNewFile() ) {
>     // Case insensitive but name preserving
>   } else {
>     // case sensitive
>   }
> } else {
>  // case insensitive
> }
>
> Maybe someone else has a better idea ?

A good generic solution.

Was wondering, could there be a Use Case where FtpServer is being
purely used for Read-Only purpose (running from an account with RX
permission) and may not have write permission. (Assuming logging is
disabled or to a common folder).

Is OS name not sufficient for this? Agree that it leads to hard-coding.

- ashish

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Mar 2, 2009 at 11:52 AM, Ashish <pa...@gmail.com> wrote:
> Can't we create the name like File file = new
> File("FiLe"+System.currentTimeMillis());
> check if it exists. Chance are very rare that it will.
>
> If it exist recreate a new file name.
> If it doesn't exist, we call file.createNewFile(); and do the case
> sensitive stuff.

Problem is, we might be running on a read-only file system. Or, as
common with FTP servers, file systems that is being monitored by other
applications (over FTP or locally).

>> Would that work? Step 4 would mean taking a performance penalty if
>> there are lots of files in the parent directory, but it should not be
>> a very common case.
>
> I hope, we would be doing this once, to establish if File System is
> case sensitive or not.
> So performance shouldn't really be a big cause.

Problem is, we don't know where file systems (as in the *nix sense)
change as you can mount or link file systems together where ever. So,
we pretty much have to do this on every equals... currently we don't
use equals so much so it would probably be okay, but the Javadoc must
come with a huge warning post if we decide to go with any of these
ideas for checking file equivalence.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Ashish <pa...@gmail.com>.
On Mon, Mar 2, 2009 at 4:00 PM, Niklas Gustavsson <ni...@protocol7.com> wrote:
> On Mon, Mar 2, 2009 at 11:01 AM, Emmanuel Lecharny <el...@apache.org> wrote:
>> Nah, i'm wrong. I'm confusing the two issues : the socket error and the case
>> sensitive directory error.
>
> Damn. Okay, think out loud, could we do an equals implementation that:
>
> 1. Check if equals return true, if so, return true
> 2. Else, check if File.getName() is equal ignoring case. If not,
> return false (this is just an optimization to skip the remaining steps
> for most cases)
> 3. Check if File.exists() returns true for both casings
> 4. Do a file listing on the parent, if we get exactly one match on the
> file name (case insensitive matching), we return true
> 5. Else return false

Can't we create the name like File file = new
File("FiLe"+System.currentTimeMillis());
check if it exists. Chance are very rare that it will.

If it exist recreate a new file name.
If it doesn't exist, we call file.createNewFile(); and do the case
sensitive stuff.

I doubt it has made life simple :-(

>
> Would that work? Step 4 would mean taking a performance penalty if
> there are lots of files in the parent directory, but it should not be
> a very common case.

I hope, we would be doing this once, to establish if File System is
case sensitive or not.
So performance shouldn't really be a big cause.

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Mar 2, 2009 at 11:19 AM, Maarten Bosteels
<mb...@gmail.com> wrote:
> But even when it's not fixed in java 6...
> When it's a JVM bug on OS X, and there is no clean work-around, then IMO we
> shouldn't jumpt through too many hoops trying to solve it.

I'm not sure we can really claim this to be a bug in the JVM (even
though I think it is). I had hoped that Apple would have acknowledge
the limitation as a and fixed it, but I guess not.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Mar 2, 2009 at 11:01 AM, Emmanuel Lecharny <el...@apache.org> wrote:
> Nah, i'm wrong. I'm confusing the two issues : the socket error and the case
> sensitive directory error.

Damn. Okay, think out loud, could we do an equals implementation that:

1. Check if equals return true, if so, return true
2. Else, check if File.getName() is equal ignoring case. If not,
return false (this is just an optimization to skip the remaining steps
for most cases)
3. Check if File.exists() returns true for both casings
4. Do a file listing on the parent, if we get exactly one match on the
file name (case insensitive matching), we return true
5. Else return false

Would that work? Step 4 would mean taking a performance penalty if
there are lots of files in the parent directory, but it should not be
a very common case.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Maarten Bosteels <mb...@gmail.com>.
But even when it's not fixed in java 6...
When it's a JVM bug on OS X, and there is no clean work-around, then IMO we
shouldn't jumpt through too many hoops trying to solve it.

Maarten

On Mon, Mar 2, 2009 at 11:01 AM, Emmanuel Lecharny <el...@apache.org>wrote:

> Niklas Gustavsson wrote:
>
>> On Sun, Mar 1, 2009 at 11:06 PM, Emmanuel Lecharny <el...@apache.org>
>> wrote:
>>
>>
>>>  I'm not
>>>> really happy with this but I can't figure out a better way, besides
>>>> someone fixing the JVM.
>>>>
>>>>
>>> Btw, it's fixed in Java 6 on Mac OSX, AFAICT. The biggest issue is that
>>> you
>>> can't run this JVM on OS X 10.4.
>>>
>>>
>>
>> Really? If so, I'll be happy to declare this a known issue with Java
>> 1.5 on OS X (like the problem we had with NIO) and closing it from out
>> point of view.
>>
>>
> Nah, i'm wrong. I'm confusing the two issues : the socket error and the
> case sensitive directory error.
>
> The first one is fixed on Java 6, but not the second one...
>
>
> --
> --
> cordialement, regards,
> Emmanuel Lécharny
> www.iktek.com
> directory.apache.org
>
>
>

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> On Sun, Mar 1, 2009 at 11:06 PM, Emmanuel Lecharny <el...@apache.org> wrote:
>   
>>>  I'm not
>>> really happy with this but I can't figure out a better way, besides
>>> someone fixing the JVM.
>>>       
>> Btw, it's fixed in Java 6 on Mac OSX, AFAICT. The biggest issue is that you
>> can't run this JVM on OS X 10.4.
>>     
>
> Really? If so, I'll be happy to declare this a known issue with Java
> 1.5 on OS X (like the problem we had with NIO) and closing it from out
> point of view.
>   
Nah, i'm wrong. I'm confusing the two issues : the socket error and the 
case sensitive directory error.

The first one is fixed on Java 6, but not the second one...

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Sun, Mar 1, 2009 at 11:06 PM, Emmanuel Lecharny <el...@apache.org> wrote:
>>  I'm not
>> really happy with this but I can't figure out a better way, besides
>> someone fixing the JVM.
>
> Btw, it's fixed in Java 6 on Mac OSX, AFAICT. The biggest issue is that you
> can't run this JVM on OS X 10.4.

Really? If so, I'll be happy to declare this a known issue with Java
1.5 on OS X (like the problem we had with NIO) and closing it from out
point of view.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> On Fri, Feb 27, 2009 at 1:36 PM, Emmanuel Lecharny <el...@apache.org> wrote:
>   
>>> Given a file name which might not be in the correct casing, is there a
>>> way to detect the "real" casing in HSF+? For example, what would the
>>> following return?
>>> new File("FOO").getName()
>>> new File("FOO").getAbsolutePath()
>>> new File("FOO").getCanonicalPath()
>>> new File("FOO").getPath()
>>>
>>>       
>> The name is kept. You will have FOO for all those guys.
>>     
>
> Sucks. This is true also if "foo" exists right?
>   
yep.
>> Now, to detect if the underlying FS is case insensitive, I found that doing
>> something like :
>>
>> File f1 = new File( "test" );
>> File f2 = new File( "TEST" );
>>
>> if ( !f1.equals( f2 ) ) {
>>   if ( f1.createNewFile() != f2.createNewFile() ) {
>>     // Case insensitive but name preserving
>>   } else {
>>     // case sensitive
>>   }
>> } else {
>>  // case insensitive
>> }
>>     
>
> Since different directories might come from different file systems,
> with different case handling, we would have to do this for each call
> to equals (and potentially other methods where this matters). And, as
> Ashish points out, we might be in a read-only directory.
Yeah, that would suck...
>  I'm not
> really happy with this but I can't figure out a better way, besides
> someone fixing the JVM.
Btw, it's fixed in Java 6 on Mac OSX, AFAICT. The biggest issue is that 
you can't run this JVM on OS X 10.4.

Mac is not as cool as it seems to be. Not only their keybord and mouse 
sucks, but their Java policy stinks like a dead fish... IMHO, of course :)

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Feb 27, 2009 at 1:36 PM, Emmanuel Lecharny <el...@apache.org> wrote:
>> Given a file name which might not be in the correct casing, is there a
>> way to detect the "real" casing in HSF+? For example, what would the
>> following return?
>> new File("FOO").getName()
>> new File("FOO").getAbsolutePath()
>> new File("FOO").getCanonicalPath()
>> new File("FOO").getPath()
>>
>
> The name is kept. You will have FOO for all those guys.

Sucks. This is true also if "foo" exists right?

> Now, to detect if the underlying FS is case insensitive, I found that doing
> something like :
>
> File f1 = new File( "test" );
> File f2 = new File( "TEST" );
>
> if ( !f1.equals( f2 ) ) {
>   if ( f1.createNewFile() != f2.createNewFile() ) {
>     // Case insensitive but name preserving
>   } else {
>     // case sensitive
>   }
> } else {
>  // case insensitive
> }

Since different directories might come from different file systems,
with different case handling, we would have to do this for each call
to equals (and potentially other methods where this matters). And, as
Ashish points out, we might be in a read-only directory. I'm not
really happy with this but I can't figure out a better way, besides
someone fixing the JVM. Not that that is very likely of course. There
is an interesting discussion on this topic over here
http://lists.apple.com/archives/java-dev/2004/Feb/msg00331.html but it
merely makes to whole thing more complex, rather than find any
solutions. They also refers to a bug reported to Apple, but I always
fail to access their bug management tool so I haven't checked it out.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> On Fri, Feb 27, 2009 at 12:04 PM, Emmanuel Lecharny
> <el...@apache.org> wrote:
>   
>> Files are considered as different.
>>     
>
> This makes our task somewhat harder :-) So, on OS X, if we got a
> directory (or file I assume) called "foo", the following will be
> correct, right?
>
> new File("foo").equals(new File("FOO")) => false
>   
Correct
> new File("FOO").delete() => true
>   
correct
> Given a file name which might not be in the correct casing, is there a
> way to detect the "real" casing in HSF+? For example, what would the
> following return?
> new File("FOO").getName()
> new File("FOO").getAbsolutePath()
> new File("FOO").getCanonicalPath()
> new File("FOO").getPath()
>   
The name is kept. You will have FOO for all those guys.

Now, to detect if the underlying FS is case insensitive, I found that 
doing something like :

File f1 = new File( "test" );
File f2 = new File( "TEST" );

if ( !f1.equals( f2 ) ) {
    if ( f1.createNewFile() != f2.createNewFile() ) {
      // Case insensitive but name preserving
    } else {
      // case sensitive
    }
} else {
  // case insensitive
}

Maybe someone else has a better idea ?

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Feb 27, 2009 at 12:04 PM, Emmanuel Lecharny
<el...@apache.org> wrote:
> Files are considered as different.

This makes our task somewhat harder :-) So, on OS X, if we got a
directory (or file I assume) called "foo", the following will be
correct, right?

new File("foo").equals(new File("FOO")) => false
new File("FOO").delete() => true

Given a file name which might not be in the correct casing, is there a
way to detect the "real" casing in HSF+? For example, what would the
following return?
new File("FOO").getName()
new File("FOO").getAbsolutePath()
new File("FOO").getCanonicalPath()
new File("FOO").getPath()

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> On Fri, Feb 27, 2009 at 11:36 AM, Emmanuel Lecharny
> <el...@apache.org> wrote:
>   
>> Ok, we have run the tests again and the problem is that using HSF+ file
>> system on Mac, the RMD command in the testRmdirCurrentWorkingDirectory test
>> simply succeed, because HSF+ can be set to be case-insensitive.
>>     
>
> That's bad, because FtpServer should never allow deleting the current
> working directory. Would you be able to see what happens in
> org.apache.ftpserver.command.impl.RMD line 97 and in
> org.apache.ftpserver.filesystem.nativefs.impl.NativeFtpFile.equals(Object)
> when this command is sent?
Files are considered as different.



-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Feb 27, 2009 at 11:36 AM, Emmanuel Lecharny
<el...@apache.org> wrote:
> Ok, we have run the tests again and the problem is that using HSF+ file
> system on Mac, the RMD command in the testRmdirCurrentWorkingDirectory test
> simply succeed, because HSF+ can be set to be case-insensitive.

That's bad, because FtpServer should never allow deleting the current
working directory. Would you be able to see what happens in
org.apache.ftpserver.command.impl.RMD line 97 and in
org.apache.ftpserver.filesystem.nativefs.impl.NativeFtpFile.equals(Object)
when this command is sent? What should happen is that the equals
method should return true as the java.io.Files that gets compared
should evaluate to the same file.

> I guess that the FtpServer check the underlying file-system during
> initialization, and if it's a linux based one, it considers the FS as case
> sensitive.

No, at least we're not that stupid ;-)

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Julien Vermillard wrote:
>>> Would you be able to send me the debug level log for this failing
>>> test? 
>>>       
>> Will do asap.
>>     

Ok, we have run the tests again and the problem is that using HSF+ file 
system on Mac, the RMD command in the testRmdirCurrentWorkingDirectory 
test simply succeed, because HSF+ can be set to be case-insensitive.

On windows, the test passes.

I guess that the FtpServer check the underlying file-system during 
initialization, and if it's a linux based one, it considers the FS as 
case sensitive.

If this is the case (I didn't read the FtpServer internals), one 
solution would be to check wether the underlying FS is case sensitive or 
not before starting the server.


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Julien Vermillard <jv...@archean.fr>.
Le Fri, 27 Feb 2009 09:37:24 +0100,
Emmanuel Lecharny <el...@apache.org> a écrit :

> Niklas Gustavsson wrote:
> > On Fri, Feb 27, 2009 at 1:17 AM, Emmanuel Lecharny
> > <el...@apache.org> wrote: 
> >> We haved conducted more tests this afternoon, using another JVM on
> >> Mac OS X 10.5 (java 6), and didn't had the same problem.
> >>     
> >
> > Sounds like we can conclude that it's a JVM bug then.
> >   
> 
> This is also my opinion...
> >   
> >> Here is the failing test in
> >> this case :
> >>     
> >
> > Would you be able to send me the debug level log for this failing
> > test? 
> Will do asap.
> > Damn, I need to get myself a Mac :-)
> >   
> Well, considering how crappy is the JVM on these machines ... :)

Get a Mac running Linux ;)
Julien

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Niklas Gustavsson wrote:
> On Fri, Feb 27, 2009 at 1:17 AM, Emmanuel Lecharny <el...@apache.org> wrote:
>   
>> We haved conducted more tests this afternoon, using another JVM on Mac OS X
>> 10.5 (java 6), and didn't had the same problem.
>>     
>
> Sounds like we can conclude that it's a JVM bug then.
>   

This is also my opinion...
>   
>> Here is the failing test in
>> this case :
>>     
>
> Would you be able to send me the debug level log for this failing test?
>   
Will do asap.
> Damn, I need to get myself a Mac :-)
>   
Well, considering how crappy is the JVM on these machines ... :)


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Fri, Feb 27, 2009 at 1:17 AM, Emmanuel Lecharny <el...@apache.org> wrote:
> We haved conducted more tests this afternoon, using another JVM on Mac OS X
> 10.5 (java 6), and didn't had the same problem.

Sounds like we can conclude that it's a JVM bug then.

> Here is the failing test in
> this case :

Would you be able to send me the debug level log for this failing test?

Damn, I need to get myself a Mac :-)

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
We haved conducted more tests this afternoon, using another JVM on Mac 
OS X 10.5 (java 6), and didn't had the same problem. Here is the failing 
test in this case :

-------------------------------------------------------------------------------
Test set: org.apache.ftpserver.clienttests.RmDirTest
-------------------------------------------------------------------------------
Tests run: 7, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.076 sec <<< FAILURE!
testRmdirCurrentWorkingDirectory(org.apache.ftpserver.clienttests.RmDirTest)  Time elapsed: 0.014 sec  <<< FAILURE!
junit.framework.AssertionFailedError: expected:<false> but was:<true>
	at junit.framework.Assert.fail(Assert.java:47)
	at junit.framework.Assert.failNotEquals(Assert.java:280)
	at junit.framework.Assert.assertEquals(Assert.java:64)
	at junit.framework.Assert.assertEquals(Assert.java:146)
	at junit.framework.Assert.assertEquals(Assert.java:152)
	at org.apache.ftpserver.clienttests.RmDirTest.testRmdirCurrentWorkingDirectory(RmDirTest.java:119)




Guillaume Nodet wrote:
> On OS X, the test does not behave the same way: the session is created
> and the byte written, but the server does not have any managed session
> so the last assertion fails.
> To make this test fail as expected, I need to add the following calls
> to AbstractPollingIoAcceptor#unbind0
>
>         startupAcceptor();
>         wakeup();
>
> I may have an explanation.   In the unregisterHandles() method, the
> handle is closed and then there is a call to wakeup().  However, when
> the last bound socket is unregistered, the Acceptor#run() method will
> simply exit just after the call to unregisterHandles() because
> nHandles == 0.   So I think the call to wakeup() has no effect at all,
> because the acceptor is not running anymore, thus no select() call is
> performed.
>
> I've also tried the following patch:
>
> Index: core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
> ===================================================================
> --- core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
>      (revision 747700)
> +++ core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
>      (working copy)
> @@ -406,6 +406,7 @@
>                      }
>
>                      // check to see if any cancellation request has been made.
> +                    int nbPreviousHandles = nHandles;
>                      nHandles -= unregisterHandles();
>
>                      // Now, if the number of registred handles is 0, we can
> @@ -415,6 +416,9 @@
>                          synchronized (lock) {
>                              if (registerQueue.isEmpty()
>                                      && cancelQueue.isEmpty()) {
> +                                if (nbPreviousHandles > 0) {
> +                                    select();
> +                                }
>                                  acceptor = null;
>                                  break;
>                              }
>
> But I don't think it's very clean either.
>
> Note that the problem also happen with datagram sockets and none of
> the above solution seems to work in that case.
>
> 2009/2/25 Emmanuel Lecharny <el...@apache.org>:
>   
>> Guillaume Nodet wrote:
>>     
>>> I've just spotted that the acceptor is not correctly disposed.
>>> I've managed to get the test running succesfully by adding the
>>> following code just after server.suspend()
>>>
>>>        for (Listener listener :
>>> server.getServerContext().getListeners().values()) {
>>>            if (listener instanceof NioListener) {
>>>                Field field = listener.getClass().getDeclaredField("acceptor");
>>>                field.setAccessible(true);
>>>                NioSocketAcceptor acceptor = (NioSocketAcceptor)
>>> field.get(listener);
>>>                Method method =
>>> AbstractPollingIoAcceptor.class.getDeclaredMethod("dispose0");
>>>                method.setAccessible(true);
>>>                method.invoke(acceptor);
>>>            }
>>>        }
>>>
>>> Which is about callling the dispose0() method of the NioSocketAcceptor.
>>> This method looks like:
>>>
>>>    protected IoFuture dispose0() throws Exception {
>>>        unbind();
>>>        if (!disposalFuture.isDone()) {
>>>            startupAcceptor();
>>>            wakeup();
>>>        }
>>>        return disposalFuture;
>>>    }
>>>
>>> So I guess what we're missing is a call to:
>>>            startupAcceptor();
>>>            wakeup();
>>> somewhere.
>>> I'm not too familiar with mina internals, so I'm not sure where this
>>> methods should be called or if it makes any sense to call those after
>>> an unbind.
>>>
>>>       
>> The problem is that when you do an acceptor.unbind(), here is what MINA does :
>>
>> acceptor.unbind() -->
>>  unbind(getLocalAddresses()) -->
>>   unbind0(localAddressesCopy) with
>>
>>   protected final void unbind0(List<? extends SocketAddress> localAddresses)
>>           throws Exception {
>>       AcceptorOperationFuture future = new AcceptorOperationFuture(
>>               localAddresses);
>>
>>       cancelQueue.add(future);
>>       startupAcceptor();
>>       wakeup();
>>       ...
>>
>> There is obviously something wrong somewhere, if you consider the following test :
>> org.apache.mina.transport.AbstractBindTest
>>
>>   public void testUnbindDisconnectsClients() throws Exception {
>>       bind(true);
>>       IoConnector connector = newConnector();
>>       IoSession[] sessions = new IoSession[5];
>>       connector.setHandler(new IoHandlerAdapter());
>>
>>       // Create 5 sessions, and write when established
>>       for (int i = 0; i < sessions.length; i++) {
>>           ConnectFuture future = connector.connect(createSocketAddress(port));
>>           future.awaitUninterruptibly();
>>           sessions[i] = future.getSession();
>>           Assert.assertTrue(sessions[i].isConnected());
>>           Assert.assertTrue(sessions[i].write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());
>>       }
>>
>>       // Wait for the server side sessions to be created.
>>       Thread.sleep(500);
>>
>>       Collection<IoSession> managedSessions = acceptor.getManagedSessions().values();
>>       Assert.assertEquals(5, managedSessions.size());
>>
>>       // Now unbind
>>       acceptor.unbind();
>>
>>       // Wait for the accessor to unbind
>>       Thread.sleep(500);
>>
>>       // The session must have been closed
>>       Assert.assertEquals(0, managedSessions.size());
>>       for (IoSession element : managedSessions) {
>>           Assert.assertFalse(element.isConnected());
>>       }
>>
>>       // And now, try to create a session on a unbound acceptor !!!
>>       ConnectFuture future = connector.connect(createSocketAddress(port));
>>       future.awaitUninterruptibly();
>>       IoSession session = future.getSession();
>>       Assert.assertTrue(session.isConnected());
>>       Assert.assertTrue(session.write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());
>>
>>       // Wait for the server side sessions to be created.
>>       Thread.sleep(500);
>>
>>       managedSessions = acceptor.getManagedSessions().values();
>>       Assert.assertEquals(1, managedSessions.size());
>>   }
>>
>>
>> On Linux, this tests passes, all lights green !
>>
>> --
>> --
>> cordialement, regards,
>> Emmanuel Lécharny
>> www.iktek.com
>> directory.apache.org
>>
>>
>>
>>     
>
>
>
>   


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Guillaume Nodet wrote:
> On OS X, the test does not behave the same way: the session is created
> and the byte written, but the server does not have any managed session
> so the last assertion fails.
>   
Can someone test the code with Mac OS x 1.0.5/Java 6 ?


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Guillaume Nodet wrote:
> On OS X, the test does not behave the same way: the session is created
> and the byte written, but the server does not have any managed session
> so the last assertion fails.
> To make this test fail as expected, I need to add the following calls
> to AbstractPollingIoAcceptor#unbind0
>
>         startupAcceptor();
>         wakeup();
>
> I may have an explanation.   In the unregisterHandles() method, the
> handle is closed and then there is a call to wakeup().  However, when
> the last bound socket is unregistered, the Acceptor#run() method will
> simply exit just after the call to unregisterHandles() because
> nHandles == 0.   So I think the call to wakeup() has no effect at all,
> because the acceptor is not running anymore, thus no select() call is
> performed.
>   
Sounds to me like it's a big F**** mess...

A global review may be needed !

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Guillaume Nodet <gn...@gmail.com>.
On OS X, the test does not behave the same way: the session is created
and the byte written, but the server does not have any managed session
so the last assertion fails.
To make this test fail as expected, I need to add the following calls
to AbstractPollingIoAcceptor#unbind0

        startupAcceptor();
        wakeup();

I may have an explanation.   In the unregisterHandles() method, the
handle is closed and then there is a call to wakeup().  However, when
the last bound socket is unregistered, the Acceptor#run() method will
simply exit just after the call to unregisterHandles() because
nHandles == 0.   So I think the call to wakeup() has no effect at all,
because the acceptor is not running anymore, thus no select() call is
performed.

I've also tried the following patch:

Index: core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
===================================================================
--- core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
     (revision 747700)
+++ core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
     (working copy)
@@ -406,6 +406,7 @@
                     }

                     // check to see if any cancellation request has been made.
+                    int nbPreviousHandles = nHandles;
                     nHandles -= unregisterHandles();

                     // Now, if the number of registred handles is 0, we can
@@ -415,6 +416,9 @@
                         synchronized (lock) {
                             if (registerQueue.isEmpty()
                                     && cancelQueue.isEmpty()) {
+                                if (nbPreviousHandles > 0) {
+                                    select();
+                                }
                                 acceptor = null;
                                 break;
                             }

But I don't think it's very clean either.

Note that the problem also happen with datagram sockets and none of
the above solution seems to work in that case.

2009/2/25 Emmanuel Lecharny <el...@apache.org>:
> Guillaume Nodet wrote:
>>
>> I've just spotted that the acceptor is not correctly disposed.
>> I've managed to get the test running succesfully by adding the
>> following code just after server.suspend()
>>
>>        for (Listener listener :
>> server.getServerContext().getListeners().values()) {
>>            if (listener instanceof NioListener) {
>>                Field field = listener.getClass().getDeclaredField("acceptor");
>>                field.setAccessible(true);
>>                NioSocketAcceptor acceptor = (NioSocketAcceptor)
>> field.get(listener);
>>                Method method =
>> AbstractPollingIoAcceptor.class.getDeclaredMethod("dispose0");
>>                method.setAccessible(true);
>>                method.invoke(acceptor);
>>            }
>>        }
>>
>> Which is about callling the dispose0() method of the NioSocketAcceptor.
>> This method looks like:
>>
>>    protected IoFuture dispose0() throws Exception {
>>        unbind();
>>        if (!disposalFuture.isDone()) {
>>            startupAcceptor();
>>            wakeup();
>>        }
>>        return disposalFuture;
>>    }
>>
>> So I guess what we're missing is a call to:
>>            startupAcceptor();
>>            wakeup();
>> somewhere.
>> I'm not too familiar with mina internals, so I'm not sure where this
>> methods should be called or if it makes any sense to call those after
>> an unbind.
>>
>
> The problem is that when you do an acceptor.unbind(), here is what MINA does :
>
> acceptor.unbind() -->
>  unbind(getLocalAddresses()) -->
>   unbind0(localAddressesCopy) with
>
>   protected final void unbind0(List<? extends SocketAddress> localAddresses)
>           throws Exception {
>       AcceptorOperationFuture future = new AcceptorOperationFuture(
>               localAddresses);
>
>       cancelQueue.add(future);
>       startupAcceptor();
>       wakeup();
>       ...
>
> There is obviously something wrong somewhere, if you consider the following test :
> org.apache.mina.transport.AbstractBindTest
>
>   public void testUnbindDisconnectsClients() throws Exception {
>       bind(true);
>       IoConnector connector = newConnector();
>       IoSession[] sessions = new IoSession[5];
>       connector.setHandler(new IoHandlerAdapter());
>
>       // Create 5 sessions, and write when established
>       for (int i = 0; i < sessions.length; i++) {
>           ConnectFuture future = connector.connect(createSocketAddress(port));
>           future.awaitUninterruptibly();
>           sessions[i] = future.getSession();
>           Assert.assertTrue(sessions[i].isConnected());
>           Assert.assertTrue(sessions[i].write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());
>       }
>
>       // Wait for the server side sessions to be created.
>       Thread.sleep(500);
>
>       Collection<IoSession> managedSessions = acceptor.getManagedSessions().values();
>       Assert.assertEquals(5, managedSessions.size());
>
>       // Now unbind
>       acceptor.unbind();
>
>       // Wait for the accessor to unbind
>       Thread.sleep(500);
>
>       // The session must have been closed
>       Assert.assertEquals(0, managedSessions.size());
>       for (IoSession element : managedSessions) {
>           Assert.assertFalse(element.isConnected());
>       }
>
>       // And now, try to create a session on a unbound acceptor !!!
>       ConnectFuture future = connector.connect(createSocketAddress(port));
>       future.awaitUninterruptibly();
>       IoSession session = future.getSession();
>       Assert.assertTrue(session.isConnected());
>       Assert.assertTrue(session.write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());
>
>       // Wait for the server side sessions to be created.
>       Thread.sleep(500);
>
>       managedSessions = acceptor.getManagedSessions().values();
>       Assert.assertEquals(1, managedSessions.size());
>   }
>
>
> On Linux, this tests passes, all lights green !
>
> --
> --
> cordialement, regards,
> Emmanuel Lécharny
> www.iktek.com
> directory.apache.org
>
>
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/
------------------------
Open Source SOA
http://fusesource.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Guillaume Nodet wrote:
> I've just spotted that the acceptor is not correctly disposed.
> I've managed to get the test running succesfully by adding the
> following code just after server.suspend()
>
>         for (Listener listener :
> server.getServerContext().getListeners().values()) {
>             if (listener instanceof NioListener) {
>                 Field field = listener.getClass().getDeclaredField("acceptor");
>                 field.setAccessible(true);
>                 NioSocketAcceptor acceptor = (NioSocketAcceptor)
> field.get(listener);
>                 Method method =
> AbstractPollingIoAcceptor.class.getDeclaredMethod("dispose0");
>                 method.setAccessible(true);
>                 method.invoke(acceptor);
>             }
>         }
>
> Which is about callling the dispose0() method of the NioSocketAcceptor.
> This method looks like:
>
>     protected IoFuture dispose0() throws Exception {
>         unbind();
>         if (!disposalFuture.isDone()) {
>             startupAcceptor();
>             wakeup();
>         }
>         return disposalFuture;
>     }
>
> So I guess what we're missing is a call to:
>             startupAcceptor();
>             wakeup();
> somewhere.
> I'm not too familiar with mina internals, so I'm not sure where this
> methods should be called or if it makes any sense to call those after
> an unbind.
>   
The problem is that when you do an acceptor.unbind(), here is what MINA 
does :

acceptor.unbind() -->
  unbind(getLocalAddresses()) -->
    unbind0(localAddressesCopy) with

    protected final void unbind0(List<? extends SocketAddress> 
localAddresses)
            throws Exception {
        AcceptorOperationFuture future = new AcceptorOperationFuture(
                localAddresses);

        cancelQueue.add(future);
        startupAcceptor();
        wakeup();
        ...

There is obviously something wrong somewhere, if you consider the 
following test :
org.apache.mina.transport.AbstractBindTest

    public void testUnbindDisconnectsClients() throws Exception {
        bind(true);
        IoConnector connector = newConnector();
        IoSession[] sessions = new IoSession[5];
        connector.setHandler(new IoHandlerAdapter());

        // Create 5 sessions, and write when established
        for (int i = 0; i < sessions.length; i++) {
            ConnectFuture future = 
connector.connect(createSocketAddress(port));
            future.awaitUninterruptibly();
            sessions[i] = future.getSession();
            Assert.assertTrue(sessions[i].isConnected());
            
Assert.assertTrue(sessions[i].write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());
        }

        // Wait for the server side sessions to be created.
        Thread.sleep(500);

        Collection<IoSession> managedSessions = 
acceptor.getManagedSessions().values();
        Assert.assertEquals(5, managedSessions.size());

        // Now unbind
        acceptor.unbind();

        // Wait for the accessor to unbind
        Thread.sleep(500);

        // The session must have been closed
        Assert.assertEquals(0, managedSessions.size());
        for (IoSession element : managedSessions) {
            Assert.assertFalse(element.isConnected());
        }

        // And now, try to create a session on a unbound acceptor !!!
        ConnectFuture future = connector.connect(createSocketAddress(port));
        future.awaitUninterruptibly();
        IoSession session = future.getSession();
        Assert.assertTrue(session.isConnected());
        
Assert.assertTrue(session.write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());

        // Wait for the server side sessions to be created.
        Thread.sleep(500);

        managedSessions = acceptor.getManagedSessions().values();
        Assert.assertEquals(1, managedSessions.size());
    }


On Linux, this tests passes, all lights green !

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Guillaume Nodet <gn...@gmail.com>.
I've just spotted that the acceptor is not correctly disposed.
I've managed to get the test running succesfully by adding the
following code just after server.suspend()

        for (Listener listener :
server.getServerContext().getListeners().values()) {
            if (listener instanceof NioListener) {
                Field field = listener.getClass().getDeclaredField("acceptor");
                field.setAccessible(true);
                NioSocketAcceptor acceptor = (NioSocketAcceptor)
field.get(listener);
                Method method =
AbstractPollingIoAcceptor.class.getDeclaredMethod("dispose0");
                method.setAccessible(true);
                method.invoke(acceptor);
            }
        }

Which is about callling the dispose0() method of the NioSocketAcceptor.
This method looks like:

    protected IoFuture dispose0() throws Exception {
        unbind();
        if (!disposalFuture.isDone()) {
            startupAcceptor();
            wakeup();
        }
        return disposalFuture;
    }

So I guess what we're missing is a call to:
            startupAcceptor();
            wakeup();
somewhere.
I'm not too familiar with mina internals, so I'm not sure where this
methods should be called or if it makes any sense to call those after
an unbind.


2009/2/24 Emmanuel Lecharny <el...@apache.org>:
> On Tue, Feb 24, 2009 at 4:36 PM, Guillaume Nodet <gn...@gmail.com> wrote:
>> Maybe not the suspend call directly, but as a side effect.
>> If the server is not started, the correct expceiton if thrown by the client.
>> If the server is suspended and restarted, then the client connects correctly.
>
> yeah, probably. I suspect that the acceptor is not stopped correctly.
> --
> Regards,
> Cordialement,
> Emmanuel Lécharny
> www.iktek.com
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/
------------------------
Open Source SOA
http://fusesource.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
On Tue, Feb 24, 2009 at 4:36 PM, Guillaume Nodet <gn...@gmail.com> wrote:
> Maybe not the suspend call directly, but as a side effect.
> If the server is not started, the correct expceiton if thrown by the client.
> If the server is suspended and restarted, then the client connects correctly.

yeah, probably. I suspect that the acceptor is not stopped correctly.
-- 
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Guillaume Nodet <gn...@gmail.com>.
Maybe not the suspend call directly, but as a side effect.
If the server is not started, the correct expceiton if thrown by the client.
If the server is suspended and restarted, then the client connects correctly.

2009/2/24 Emmanuel Lecharny <el...@apache.org>:
> On Tue, Feb 24, 2009 at 3:45 PM, Guillaume Nodet <gn...@gmail.com> wrote:
>> This explanation is more in line with what I found.  I'm not sure
>> either why the socket connection works.  I've tried to add a sleep
>> between the suspend and connect but to no avail.
>
> I don't think that the suspend is the origin of the problem.
>
> I will do some more debugging on Mac in a few hours. seems like the
> socket.connect() hangs, but I don't know if the acceptor receives any
> incoming request.
>
> I'm wondering if there is not a big issue in the
> AbstractPollingIoAcceptor.Acceptor.run() method :
> ...
>                    // Now, if the number of registred handles is 0, we can
>                    // quit the loop: we don't have any socket listening
>                    // for incoming connection.
>                    if (nHandles == 0) {
>                        synchronized (lock) {
>                            if (registerQueue.isEmpty()
>                                    && cancelQueue.isEmpty()) {
>                                acceptor = null;
>                                break;
>                            }
>                        }
>                    }
> ...
>
> when we call the server.suspend() method. If we don't get out of the
> loop, or if the lock is handled by some other thread, we might have a
> problem. As I don't have a mac here, I can't check atm.
>
>
>>
>> 2009/2/24 Emmanuel Lecharny <el...@apache.org>:
>>> Ok, I have been able to go a bit further on Windows.
>>>
>>> The slector.keys().isEmpty() returns true too, so we also exit from
>>> the server acceptor loop.
>>>
>>> When the client tries to connect again, it can't and an exception is
>>> thrown (which is expected).
>>>
>>> As far as I remember, on mac, this is where the test blcok : the
>>>
>>>        try {
>>>            client.connect("localhost", port);
>>>
>>> code waits forever, when it should get out immediately with this exception :
>>>
>>>
>>> java.net.ConnectException: Connection refused: connect
>>>        at java.net.PlainSocketImpl.socketConnect(Native Method)
>>>        at java.net.PlainSocketImpl.doConnect(Unknown Source)
>>>        at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
>>>        at java.net.PlainSocketImpl.connect(Unknown Source)
>>>        at java.net.SocksSocketImpl.connect(Unknown Source)
>>>        at java.net.Socket.connect(Unknown Source)
>>>        at org.apache.commons.net.SocketClient.connect(SocketClient.java:176)
>>>        at org.apache.ftpserver.clienttests.SuspendResumeTest.testSuspendResumeServer(SuspendResumeTest.java:46)
>>>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
>>>        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
>>>        at java.lang.reflect.Method.invoke(Unknown Source)
>>>        at junit.framework.TestCase.runTest(TestCase.java:164)
>>>        at junit.framework.TestCase.runBare(TestCase.java:130)
>>>        at junit.framework.TestResult$1.protect(TestResult.java:106)
>>>        at junit.framework.TestResult.runProtected(TestResult.java:124)
>>>        at junit.framework.TestResult.run(TestResult.java:109)
>>>        at junit.framework.TestCase.run(TestCase.java:120)
>>>        at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
>>>        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>>>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
>>>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
>>>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
>>>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
>>>
>>> For some reason, it does not ... Why ???
>>>
>>> --
>>> Regards,
>>> Cordialement,
>>> Emmanuel Lécharny
>>> www.iktek.com
>>>
>>
>>
>>
>> --
>> Cheers,
>> Guillaume Nodet
>> ------------------------
>> Blog: http://gnodet.blogspot.com/
>> ------------------------
>> Open Source SOA
>> http://fusesource.com
>>
>
>
>
> --
> Regards,
> Cordialement,
> Emmanuel Lécharny
> www.iktek.com
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/
------------------------
Open Source SOA
http://fusesource.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
On Tue, Feb 24, 2009 at 3:45 PM, Guillaume Nodet <gn...@gmail.com> wrote:
> This explanation is more in line with what I found.  I'm not sure
> either why the socket connection works.  I've tried to add a sleep
> between the suspend and connect but to no avail.

I don't think that the suspend is the origin of the problem.

I will do some more debugging on Mac in a few hours. seems like the
socket.connect() hangs, but I don't know if the acceptor receives any
incoming request.

I'm wondering if there is not a big issue in the
AbstractPollingIoAcceptor.Acceptor.run() method :
...
                    // Now, if the number of registred handles is 0, we can
                    // quit the loop: we don't have any socket listening
                    // for incoming connection.
                    if (nHandles == 0) {
                        synchronized (lock) {
                            if (registerQueue.isEmpty()
                                    && cancelQueue.isEmpty()) {
                                acceptor = null;
                                break;
                            }
                        }
                    }
...

when we call the server.suspend() method. If we don't get out of the
loop, or if the lock is handled by some other thread, we might have a
problem. As I don't have a mac here, I can't check atm.


>
> 2009/2/24 Emmanuel Lecharny <el...@apache.org>:
>> Ok, I have been able to go a bit further on Windows.
>>
>> The slector.keys().isEmpty() returns true too, so we also exit from
>> the server acceptor loop.
>>
>> When the client tries to connect again, it can't and an exception is
>> thrown (which is expected).
>>
>> As far as I remember, on mac, this is where the test blcok : the
>>
>>        try {
>>            client.connect("localhost", port);
>>
>> code waits forever, when it should get out immediately with this exception :
>>
>>
>> java.net.ConnectException: Connection refused: connect
>>        at java.net.PlainSocketImpl.socketConnect(Native Method)
>>        at java.net.PlainSocketImpl.doConnect(Unknown Source)
>>        at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
>>        at java.net.PlainSocketImpl.connect(Unknown Source)
>>        at java.net.SocksSocketImpl.connect(Unknown Source)
>>        at java.net.Socket.connect(Unknown Source)
>>        at org.apache.commons.net.SocketClient.connect(SocketClient.java:176)
>>        at org.apache.ftpserver.clienttests.SuspendResumeTest.testSuspendResumeServer(SuspendResumeTest.java:46)
>>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
>>        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
>>        at java.lang.reflect.Method.invoke(Unknown Source)
>>        at junit.framework.TestCase.runTest(TestCase.java:164)
>>        at junit.framework.TestCase.runBare(TestCase.java:130)
>>        at junit.framework.TestResult$1.protect(TestResult.java:106)
>>        at junit.framework.TestResult.runProtected(TestResult.java:124)
>>        at junit.framework.TestResult.run(TestResult.java:109)
>>        at junit.framework.TestCase.run(TestCase.java:120)
>>        at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
>>        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
>>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
>>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
>>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
>>
>> For some reason, it does not ... Why ???
>>
>> --
>> Regards,
>> Cordialement,
>> Emmanuel Lécharny
>> www.iktek.com
>>
>
>
>
> --
> Cheers,
> Guillaume Nodet
> ------------------------
> Blog: http://gnodet.blogspot.com/
> ------------------------
> Open Source SOA
> http://fusesource.com
>



-- 
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Guillaume Nodet <gn...@gmail.com>.
This explanation is more in line with what I found.  I'm not sure
either why the socket connection works.  I've tried to add a sleep
between the suspend and connect but to no avail.

2009/2/24 Emmanuel Lecharny <el...@apache.org>:
> Ok, I have been able to go a bit further on Windows.
>
> The slector.keys().isEmpty() returns true too, so we also exit from
> the server acceptor loop.
>
> When the client tries to connect again, it can't and an exception is
> thrown (which is expected).
>
> As far as I remember, on mac, this is where the test blcok : the
>
>        try {
>            client.connect("localhost", port);
>
> code waits forever, when it should get out immediately with this exception :
>
>
> java.net.ConnectException: Connection refused: connect
>        at java.net.PlainSocketImpl.socketConnect(Native Method)
>        at java.net.PlainSocketImpl.doConnect(Unknown Source)
>        at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
>        at java.net.PlainSocketImpl.connect(Unknown Source)
>        at java.net.SocksSocketImpl.connect(Unknown Source)
>        at java.net.Socket.connect(Unknown Source)
>        at org.apache.commons.net.SocketClient.connect(SocketClient.java:176)
>        at org.apache.ftpserver.clienttests.SuspendResumeTest.testSuspendResumeServer(SuspendResumeTest.java:46)
>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
>        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
>        at java.lang.reflect.Method.invoke(Unknown Source)
>        at junit.framework.TestCase.runTest(TestCase.java:164)
>        at junit.framework.TestCase.runBare(TestCase.java:130)
>        at junit.framework.TestResult$1.protect(TestResult.java:106)
>        at junit.framework.TestResult.runProtected(TestResult.java:124)
>        at junit.framework.TestResult.run(TestResult.java:109)
>        at junit.framework.TestCase.run(TestCase.java:120)
>        at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
>        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
>        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
>
> For some reason, it does not ... Why ???
>
> --
> Regards,
> Cordialement,
> Emmanuel Lécharny
> www.iktek.com
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/
------------------------
Open Source SOA
http://fusesource.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Ok, I have been able to go a bit further on Windows.

The slector.keys().isEmpty() returns true too, so we also exit from
the server acceptor loop.

When the client tries to connect again, it can't and an exception is
thrown (which is expected).

As far as I remember, on mac, this is where the test blcok : the

        try {
            client.connect("localhost", port);

code waits forever, when it should get out immediately with this exception :


java.net.ConnectException: Connection refused: connect
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.PlainSocketImpl.doConnect(Unknown Source)
	at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
	at java.net.PlainSocketImpl.connect(Unknown Source)
	at java.net.SocksSocketImpl.connect(Unknown Source)
	at java.net.Socket.connect(Unknown Source)
	at org.apache.commons.net.SocketClient.connect(SocketClient.java:176)
	at org.apache.ftpserver.clienttests.SuspendResumeTest.testSuspendResumeServer(SuspendResumeTest.java:46)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at junit.framework.TestCase.runTest(TestCase.java:164)
	at junit.framework.TestCase.runBare(TestCase.java:130)
	at junit.framework.TestResult$1.protect(TestResult.java:106)
	at junit.framework.TestResult.runProtected(TestResult.java:124)
	at junit.framework.TestResult.run(TestResult.java:109)
	at junit.framework.TestCase.run(TestCase.java:120)
	at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

For some reason, it does not ... Why ???

-- 
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
On Tue, Feb 24, 2009 at 9:46 AM, Niklas Gustavsson <ni...@protocol7.com> wrote:
> On Tue, Feb 24, 2009 at 1:27 AM, Emmanuel Lecharny <el...@apache.org> wrote:
>> What's happening is that when the session is disconnected  in the test :
>
> [snip]
>>
>> In other words, the server is *dead*.
>
> So, if I understand your correctly, this happens on a client
> disconnect? That seems very odd as it would break lots and lots of NIO
> applications (and several other of the test cases in FtpServer).

This is what I see. More logs could help to analyze if there are some
timing issues...

It seems that the socketChannel is not anymore registred, even if it
should, as the selector.keys() returns an empty array.

I have to check if some strange mechanism deregister the socketChannel.

-- 
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Tue, Feb 24, 2009 at 1:27 AM, Emmanuel Lecharny <el...@apache.org> wrote:
> What's happening is that when the session is disconnected  in the test :

[snip]
>
> In other words, the server is *dead*.

So, if I understand your correctly, this happens on a client
disconnect? That seems very odd as it would break lots and lots of NIO
applications (and several other of the test cases in FtpServer).

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Some more info.

I have investigated the pb on Mac & Linux. Its behavior is different.

What's happening is that when the session is disconnected  in the test :

    public void testSuspendResumeServer() throws Exception {
        // connect should work as expected
        client.connect("localhost", port);
        client.disconnect();

the IoProcessor thread (MINA) does something different on Linux and on Mac :

    private class Processor implements Runnable {
        public void run() {
            int nSessions = 0;
            lastIdleCheckTime = System.currentTimeMillis();

            for (;;) {
                try {
                    ...
                    nSessions -= remove();
                    notifyIdleSessions(currentTime);

                    if (nSessions == 0) {
                        synchronized (lock) {
                            if (newSessions.isEmpty() && 
isSelectorEmpty()) {  <---- This is here.
                                processor = null;
                                break;

On linux, the selector is never empty. On mac, in this case, the session 
number is empty _and_ the selector keys is empty too, so we get out of 
the IoProcessor, and there is nothing left to deal with the client 
reconection.

In other words, the server is *dead*.

Sounds like a bad bug in the Mac JVM, as the isSelectorEmpty() method :
    protected boolean isSelectorEmpty() {
        return selector.keys().isEmpty();
    }

calls the selector.keys() method, which contract is :

"The key set is not directly modifiable. A key is removed only after it 
has been cancelled and its channel has been deregistered. Any attempt to 
modify the key set will cause an |UnsupportedOperationException| 
<http://java.sun.com/j2se/1.5.0/docs/api/java/lang/UnsupportedOperationException.html> 
to be thrown. "

As we are _still_ listening this channel ( remember that the server has 
not _yet_ been stopped : I'm debugging the program, and I have not yet 
step into the server.suspend() method), there is clearly something wrong 
: the channel has not been deregistred.

Is someone connected with Apple and can see if a bug report can be send, 
if I'm not totally off rails ?


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
Sorry for the polution ... There were two thread dump in the previous 
post. Here is the important one :

Full thread dump Java HotSpot(TM) Client VM (1.5.0_16-132 mixed mode, sharing):

"Low Memory Detector" daemon prio=5 tid=0x00608e60 nid=0x1815800
runnable [0x00000000..0x00000000]

"CompilerThread0" daemon prio=9 tid=0x00608480 nid=0x1815400 waiting
on condition [0x00000000..0xb0b06748]

"Signal Dispatcher" daemon prio=9 tid=0x00607fd0 nid=0x1811400 waiting
on condition [0x00000000..0x00000000]

"Finalizer" daemon prio=8 tid=0x00607780 nid=0x1808800 in
Object.wait() [0xb0a04000..0xb0a04d10]
        at java.lang.Object.wait(Native Method)
        - waiting on <0x26a8a380> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:120)
        - locked <0x26a8a380> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:136)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x006073f0 nid=0x1808400 in
Object.wait() [0xb0983000..0xb0983d10]
        at java.lang.Object.wait(Native Method)
        - waiting on <0x26a8a408> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:474)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
        - locked <0x26a8a408> (a java.lang.ref.Reference$Lock)

"main" prio=5 tid=0x006012f0 nid=0x1804a00 runnable [0xb07ff000..0xb0800138]
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at sun.nio.cs.StreamDecoder$CharsetSD.readBytes(StreamDecoder.java:411)
        at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:453)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)
        - locked <0x265e6dc0> (a java.io.InputStreamReader)
        at java.io.InputStreamReader.read(InputStreamReader.java:167)
        at java.io.BufferedReader.fill(BufferedReader.java:136)
        at java.io.BufferedReader.readLine(BufferedReader.java:299)
        - locked <0x265e6dc0> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(BufferedReader.java:362)
        at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:294)
        at org.apache.commons.net.ftp.FTP._connectAction_(FTP.java:364)
        at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:540)
        at org.apache.commons.net.SocketClient.connect(SocketClient.java:178)
        at org.apache.ftpserver.clienttests.SuspendResumeTest.testSuspendResumeServer(SuspendResumeTest.java:46)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at junit.framework.TestCase.runTest(TestCase.java:164)
        at junit.framework.TestCase.runBare(TestCase.java:130)
        at junit.framework.TestResult$1.protect(TestResult.java:106)
        at junit.framework.TestResult.runProtected(TestResult.java:124)
        at junit.framework.TestResult.run(TestResult.java:109)
        at junit.framework.TestCase.run(TestCase.java:120)
        at junit.framework.TestSuite.runTest(TestSuite.java:230)
        at junit.framework.TestSuite.run(TestSuite.java:225)
        at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:213)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
        at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
        at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)

"VM Thread" prio=9 tid=0x00606b70 nid=0x1808000 runnable

"VM Periodic Task Thread" prio=9 tid=0x00609a10 nid=0x1815c00 waiting
on condition

-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Emmanuel Lecharny <el...@apache.org>.
I confirm the pb on Mac, Java 1.5.0_16. here is a thread dump :


[] [] [] Native filesystem view created for user "null" with root
"/Users/elecharny/ftpserver-1.0/ftpserver-1.0.0/core/test-tmp/ftproot/"
[] [] [] Native filesystem view created for user "null" with root
"/Users/elecharny/ftpserver-1.0/ftpserver-1.0.0/core/test-tmp/ftproot/"
[] [] [] Native filesystem view created for user "null" with root
"/Users/elecharny/ftpserver-1.0/ftpserver-1.0.0/core/test-tmp/ftproot/"
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.011 sec
Running org.apache.ftpserver.clienttests.SuspendResumeTest
Using default port: 12321
[] [] [] File configured, will try loading
[] [] [] File found on file system
[] [] [] FTP server started
[] [127.0.0.1] [] CREATED
[] [127.0.0.1] [134a5029-ebe8-4208-80f6-a5d67d710806] OPENED
[] [] [] < 220 Service ready for new user.
[] [] [] Suspending server
[] [] [] Suspending listener
[] [127.0.0.1] [134a5029-ebe8-4208-80f6-a5d67d710806] SENT: 220
Service ready for new user.

[] [127.0.0.1] [134a5029-ebe8-4208-80f6-a5d67d710806] CLOSED
[] [] [] Listener suspended
[] [] [] Server suspended
////






::::Full thread dump Java HotSpot(TM) Client VM (1.5.0_16-132 mixed
mode, sharing):

"Thread-3" prio=5 tid=0x00645ad0 nid=0x193ec00 runnable [0xb0e0c000..0xb0e0cd10]
        at java.io.FileInputStream.readBytes(Native Method)
        at java.io.FileInputStream.read(FileInputStream.java:194)
        at sun.nio.cs.StreamDecoder$CharsetSD.readBytes(StreamDecoder.java:411)
        at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:453)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)
        - locked <0x265ad638> (a java.io.InputStreamReader)
        at java.io.InputStreamReader.read(InputStreamReader.java:167)
        at java.io.BufferedReader.fill(BufferedReader.java:136)
        at java.io.BufferedReader.readLine(BufferedReader.java:299)
        - locked <0x265ad638> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(BufferedReader.java:362)
        at org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.StreamPumper.run(StreamPumper.java:140)

"Thread-2" prio=5 tid=0x00645950 nid=0x193e800 runnable [0xb0d8b000..0xb0d8bd10]
        at java.io.FileInputStream.readBytes(Native Method)
        at java.io.FileInputStream.read(FileInputStream.java:194)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:254)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
        - locked <0x265a8708> (a java.io.BufferedInputStream)
        at sun.nio.cs.StreamDecoder$CharsetSD.readBytes(StreamDecoder.java:411)
        at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:453)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)
        - locked <0x265aab60> (a java.io.InputStreamReader)
        at java.io.InputStreamReader.read(InputStreamReader.java:167)
        at java.io.BufferedReader.fill(BufferedReader.java:136)
        at java.io.BufferedReader.readLine(BufferedReader.java:299)
        - locked <0x265aab60> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(BufferedReader.java:362)
        at org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.StreamPumper.run(StreamPumper.java:153)

"process reaper" daemon prio=5 tid=0x006457d0 nid=0x1909c00 runnable
[0xb0d0a000..0xb0d0ad10]
        at java.lang.UNIXProcess.waitForProcessExit(Native Method)
        at java.lang.UNIXProcess.access$700(UNIXProcess.java:17)
        at java.lang.UNIXProcess$2$1.run(UNIXProcess.java:83)

"Low Memory Detector" daemon prio=5 tid=0x00608f60 nid=0x1815800
runnable [0x00000000..0x00000000]

"CompilerThread0" daemon prio=9 tid=0x00608580 nid=0x1815400 waiting
on condition [0x00000000..0xb0b06748]

"Signal Dispatcher" daemon prio=9 tid=0x006080d0 nid=0x1811400 waiting
on condition [0x00000000..0x00000000]

"Finalizer" daemon prio=8 tid=0x00607890 nid=0x1810c00 in
Object.wait() [0xb0a04000..0xb0a04d10]
        at java.lang.Object.wait(Native Method)
        - waiting on <0x26a8a368> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:120)
        - locked <0x26a8a368> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:136)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x00607500 nid=0x180fe00 in
Object.wait() [0xb0983000..0xb0983d10]
        at java.lang.Object.wait(Native Method)
        - waiting on <0x26a8a3f0> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:474)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
        - locked <0x26a8a3f0> (a java.lang.ref.Reference$Lock)

"main" prio=5 tid=0x00601440 nid=0x1804a00 in Object.wait()
[0xb07ff000..0xb08000f8]
        at java.lang.Object.wait(Native Method)
        - waiting on <0x265a63c8> (a java.lang.UNIXProcess)
        at java.lang.Object.wait(Object.java:474)
        at java.lang.UNIXProcess.waitFor(UNIXProcess.java:112)
        - locked <0x265a63c8> (a java.lang.UNIXProcess)
        at org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.CommandLineUtils.executeCommandLine(CommandLineUtils.java:146)
        at org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.CommandLineUtils.executeCommandLine(CommandLineUtils.java:98)
        at org.apache.maven.surefire.booter.SurefireBooter.fork(SurefireBooter.java:673)
        at org.apache.maven.surefire.booter.SurefireBooter.forkSuites(SurefireBooter.java:479)
        at org.apache.maven.surefire.booter.SurefireBooter.runSuitesForkOnce(SurefireBooter.java:379)
        at org.apache.maven.surefire.booter.SurefireBooter.run(SurefireBooter.java:245)
        at org.apache.maven.plugin.surefire.SurefirePlugin.execute(SurefirePlugin.java:537)
        at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:451)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:558)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:499)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:478)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:330)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:291)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:142)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:336)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:129)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:287)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
        at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
        at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
        at org.codehaus.classworlds.Launcher.main(Launcher.java:375)

"VM Thread" prio=9 tid=0x00606c80 nid=0x180fa00 runnable

"VM Periodic Task Thread" prio=9 tid=0x0060a6c0 nid=0x1815c00 waiting
on condition

"Exception Catcher Thread" prio=10 tid=0x00601660 nid=0x1804e00 runnable
Full thread dump Java HotSpot(TM) Client VM (1.5.0_16-132 mixed mode, sharing):

"Low Memory Detector" daemon prio=5 tid=0x00608e60 nid=0x1815800
runnable [0x00000000..0x00000000]

"CompilerThread0" daemon prio=9 tid=0x00608480 nid=0x1815400 waiting
on condition [0x00000000..0xb0b06748]

"Signal Dispatcher" daemon prio=9 tid=0x00607fd0 nid=0x1811400 waiting
on condition [0x00000000..0x00000000]

"Finalizer" daemon prio=8 tid=0x00607780 nid=0x1808800 in
Object.wait() [0xb0a04000..0xb0a04d10]
        at java.lang.Object.wait(Native Method)
        - waiting on <0x26a8a380> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:120)
        - locked <0x26a8a380> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:136)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x006073f0 nid=0x1808400 in
Object.wait() [0xb0983000..0xb0983d10]
        at java.lang.Object.wait(Native Method)
        - waiting on <0x26a8a408> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:474)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
        - locked <0x26a8a408> (a java.lang.ref.Reference$Lock)

"main" prio=5 tid=0x006012f0 nid=0x1804a00 runnable [0xb07ff000..0xb0800138]
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at sun.nio.cs.StreamDecoder$CharsetSD.readBytes(StreamDecoder.java:411)
        at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:453)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)
        - locked <0x265e6dc0> (a java.io.InputStreamReader)
        at java.io.InputStreamReader.read(InputStreamReader.java:167)
        at java.io.BufferedReader.fill(BufferedReader.java:136)
        at java.io.BufferedReader.readLine(BufferedReader.java:299)
        - locked <0x265e6dc0> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(BufferedReader.java:362)
        at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:294)
        at org.apache.commons.net.ftp.FTP._connectAction_(FTP.java:364)
        at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:540)
        at org.apache.commons.net.SocketClient.connect(SocketClient.java:178)
        at org.apache.ftpserver.clienttests.SuspendResumeTest.testSuspendResumeServer(SuspendResumeTest.java:46)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at junit.framework.TestCase.runTest(TestCase.java:164)
        at junit.framework.TestCase.runBare(TestCase.java:130)
        at junit.framework.TestResult$1.protect(TestResult.java:106)
        at junit.framework.TestResult.runProtected(TestResult.java:124)
        at junit.framework.TestResult.run(TestResult.java:109)
        at junit.framework.TestCase.run(TestCase.java:120)
        at junit.framework.TestSuite.runTest(TestSuite.java:230)
        at junit.framework.TestSuite.run(TestSuite.java:225)
        at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:213)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
        at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
        at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)

"VM Thread" prio=9 tid=0x00606b70 nid=0x1808000 runnable

"VM Periodic Task Thread" prio=9 tid=0x00609a10 nid=0x1815c00 waiting
on condition

"Exception Catcher Thread" prio=10 tid=0x00601510 nid=0x1804e00 runnable

-- 
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Feb 23, 2009 at 12:54 PM, Guillaume Nodet <gn...@gmail.com> wrote:
> Is that what you are looking for:
>
> gnodet:~$ netstat -an | grep 12321
> tcp4       0      0  127.0.0.1.12321        127.0.0.1.50593        ESTABLISHED
> tcp4       0      0  127.0.0.1.50593        127.0.0.1.12321        ESTABLISHED
> tcp4       0      0  *.12321                *.*                    LISTEN

Yes, very much so, thanks! This shows that the server socket is still
i LISTEN state despite FtpServer asking MINA to unbind from that
address. To compare, on my Ubuntu laptop, the socket goes into
TIME_WAIT state.

Also, your client is still connected which is also weird as MINA
should have killed the session. Did your stack dump show what MINA was
doing? I think we would need to dissect in more detail what happens in
org.apache.mina.core.service.AbstractIoAcceptor.unbind(Iterable<?
extends SocketAddress>) on your machine. Would you have the time to
continue the debugging?

Anyone seen anything similar to this before? We do not do anything
fancy in FtpServer, just a simple acceptor.unbind().

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Guillaume Nodet <gn...@gmail.com>.
Is that what you are looking for:

gnodet:~$ netstat -an | grep 12321
tcp4       0      0  127.0.0.1.12321        127.0.0.1.50593        ESTABLISHED
tcp4       0      0  127.0.0.1.50593        127.0.0.1.12321        ESTABLISHED
tcp4       0      0  *.12321                *.*                    LISTEN

On Mon, Feb 23, 2009 at 12:42, Niklas Gustavsson <ni...@protocol7.com> wrote:
> On Mon, Feb 23, 2009 at 12:39 PM, Niklas Gustavsson
> <ni...@protocol7.com> wrote:
>> Commited to trunk and the 1.0.x branch. The client socket should time
>> out after 10 seconds.
>
> Note that while this might cause the test now to work (due to the
> socket timing out), that's not really fixing the problem. Getting the
> socket state would still be of interest.
>
> /niklas
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/
------------------------
Open Source SOA
http://fusesource.com

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Feb 23, 2009 at 12:39 PM, Niklas Gustavsson
<ni...@protocol7.com> wrote:
> Commited to trunk and the 1.0.x branch. The client socket should time
> out after 10 seconds.

Note that while this might cause the test now to work (due to the
socket timing out), that's not really fixing the problem. Getting the
socket state would still be of interest.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by Niklas Gustavsson <ni...@protocol7.com>.
On Mon, Feb 23, 2009 at 11:20 AM, Niklas Gustavsson
<ni...@protocol7.com> wrote:
>> The timeout on the socket is set to 0, so I suspect it will just wait
>> forever ...
>
> Well, at least longer then anyone cares to wait around. I'll set a
> shorter timeout for it.

Commited to trunk and the 1.0.x branch. The client socket should time
out after 10 seconds.

/niklas

Re: [FtpServer] Suspend problem on OSX (was Re: [VOTE] Releasing FtpServer 1.0.0)

Posted by David Latorre <dv...@gmail.com>.
2009/2/23 Niklas Gustavsson <ni...@protocol7.com>

> Moving this to it's own thread.
>
> On Mon, Feb 23, 2009 at 11:08 AM, Guillaume Nodet <gn...@gmail.com>
> wrote:
> > FWIW, the test is hanging at the following point:
>
> Looks another case of TCP/IP stacks behaving differently on different
> platforms. Would you be able to see what state the server socket is in
> when this happens (it runs on a random port so you have to look for
> the process)?
>
> > The timeout on the socket is set to 0, so I suspect it will just wait
> > forever ...
>
> Well, at least longer then anyone cares to wait around. I'll set a
> shorter timeout for it.
>

Since neither Niklas nor me have a Mac box handy, can you check this again
setting the timeout to a feasible number?