Jump to content
  • Advertisement
Sign in to follow this  

[.net] FTP protocol... LIST response?

This topic is 2774 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm building myself an FTP server, and I did alright until I got to the LIST command. I'm testing against the FileZilla client, and for some reason it insists on sending me LIST even though I've specified that my server supports MLSD.

No matter what I do, I can't get the client to accept my directory listing.
Here's the code:

                public static void HandleLISTCmd(string FTPCommand, FTPClient Client)
Client.Send(Encoding.ASCII.GetBytes("150 Opening binary data connection for file list\0"));

/*MemoryStream EPLFStream = new MemoryStream();
BinaryWriter Writer = new BinaryWriter(EPLFStream);

string[] Files = Directory.GetFiles(GlobalSettings.Default.WorkingDirectory);

foreach (string Fle in Files)




foreach (string Fle in Directory.GetFiles(GlobalSettings.Default.WorkingDirectory))
string FInfo = GenerateFileInfo(Fle);

//By now the filetransfer should be complete, so let the client know...
Client.Send(Encoding.ASCII.GetBytes("226 Transfer complete.\0"));

private static string GenerateFileInfo(string Filepath)
FileInfo FInfo = new FileInfo(Filepath);

string Size = FInfo.Length.ToString();
TimeSpan TSpan = (FInfo.LastWriteTime - new DateTime(1970, 1, 1));
string Modified = TSpan.TotalSeconds.ToString();

string ReturnStr = "+s" + Size + ",m" + Modified + ",r," + "\t" + FInfo.Name + "\0";

return ReturnStr;

private static string GenerateBinLS(string Filepath)
FileInfo FInfo = new FileInfo(Filepath);
string Result = "rw-r--r-- 1 owner group ";

Result += RightAlignString(FInfo.Length.ToString(), 13, ' ') + " ";
Result += GetMonth(FInfo.LastWriteTime.Month) + " ";

if (FInfo.LastWriteTime.Day.ToString().Length > 2)
Result += FInfo.LastWriteTime.Day.ToString() + " ";
else if (FInfo.LastWriteTime.Day.ToString().Length == 1)
Result += " " + FInfo.LastWriteTime.Day.ToString() + " ";
Result += " " + FInfo.LastWriteTime.Day.ToString() + " ";

Result += FInfo.LastWriteTime.Hour.ToString() + ":" + FInfo.LastWriteTime.Minute.ToString() + " ";

Result += FInfo.Name;

return Result;

private static string GetMonth(int Month)
switch (Month)
case 1:
return "Jan";
case 2:
return "Feb";
case 3:
return "Mar";
case 4:
return "Apr";
case 5:
return "May";
case 6:
return "Jun";
case 7:
return "Jul";
case 8:
return "Aug";
case 9:
return "Sep";
case 10:
return "Oct";
case 11:
return "Nov";
case 12:
return "Dec";

return "";

private static string RightAlignString(string sString, int nWidth, char cDelimiter)
System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();

for (int nCharacter = 0; nCharacter < nWidth - sString.Length; nCharacter++)

return stringBuilder.ToString();

I've tried using both GenerateFileInfo() and GenerateBinLS() to generate my LIST response, but no matter which one I use I get an error about the connection having timed out and that the client couldn't receive my directory listing.
I've read that the server is supposed to close the data connection, but when I try to do that FileZilla complains that the server has closed the connection.

Here is how I open my data connection:

         /// <summary>
/// Handles a PASV command in the FTP protocol.
/// PASV asks the server to open a port for data-transfer and send
/// it to the client so it can connect.
/// </summary>
/// <param name="FTPCommand"></param>
/// <param name="IP"></param>
/// <param name="Client"></param>
public static void HandlePASVCmd(string FTPCommand, string IP, FTPClient Client)
IP = IP.Replace(".", ",");

if (Client.OpenDataPort((PortNum1 * 256 + PortNum2).ToString()))
Client.Send(Encoding.ASCII.GetBytes("227 Entering Passive Mode (" + IP + "," + CalculatePort() + ")\0"));
else //This should technically never occur. See http://kb.globalscape.com/KnowledgebaseArticle10142.aspx
//for error codes.
Client.Send(Encoding.ASCII.GetBytes("425 Cannot open data connection!\0"));

private static int PortNum1 = 10;
private static int PortNum2 = 10;

private static string CalculatePort()
//The calculation is PortNum1 x 256 + PortNum2
//26100 is the port being used to listen for initial FTP connections.
if ((PortNum1 * 256) + PortNum2 != 26100)
string Result = PortNum1.ToString() + "," + PortNum2.ToString();


return Result;
PortNum1 = PortNum1 + 2;
PortNum2 = PortNum2 + 2;
return PortNum1.ToString() + "," + PortNum2.ToString();


       public bool OpenDataPort(string Port)
IPHostEntry HostEntry = Dns.GetHostByName(Dns.GetHostName());
IPAddress Address = HostEntry.AddressList[0];
Logger.LogDebug("DataAddress: " + Address.ToString());
IPEndPoint LocalEP = new IPEndPoint(Address, int.Parse(Port));

m_DatListenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_ConnectingWaitEvent = new AutoResetEvent(false);

//Don't need a high backlog, since we'll only be listening for one incoming connection.
m_DatListenerSocket.BeginAccept(new AsyncCallback(OnAcceptDataconnection), m_DatListenerSocket);
catch (SocketException)
return false;

return true;

private void OnAcceptDataconnection(IAsyncResult AR)
Socket AcceptedSocket = m_DatListenerSocket.EndAccept(AR);

if (AcceptedSocket != null)
AcceptedSocket.Blocking = false;
m_DatSenderSocket = AcceptedSocket;

Can someone please help me out? :)

Share this post

Link to post
Share on other sites
I could be totally wrong here, but I think that the list response has to come back on the data channel and not on the control channel. Something to try at least.

Share this post

Link to post
Share on other sites
Original post by MatsVed
I'm doing that!

Sry I assumed that 'Client' reference in your first block of code was a Socket object and your control channel. I would recommend logging everything you write to your control and data channels and examining that. You might also try executing client commands against a server that you know works and mimic its output. FTP is really old and as you probably noticed the documentation is ... unhelpful.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!