Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Server.cs « FtpServer - github.com/ClusterM/hakchi2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b544f8e47a2ea5d4bc544b8f3c284c8d83dee79f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace mooftpserv
{
    /// <summary>
    /// Main FTP server class. Manages the server socket, creates sessions.
    /// Can be used to configure the server.
    /// </summary>
    public class Server
    {
        // default buffer size for send/receive buffers
        private const int DEFAULT_BUFFER_SIZE = 64 * 1024;
        // default port for the server socket
        private const int DEFAULT_PORT = 21;

        private IPEndPoint endpoint;
        private int bufferSize = DEFAULT_BUFFER_SIZE;
        private IAuthHandler authHandler = null;
        private IFileSystemHandler fsHandler = null;
        private ILogHandler logHandler = null;
        private TcpListener socket = null;
        private List<Session> sessions;

        public Server()
        {
            this.endpoint = new IPEndPoint(GetDefaultAddress(), DEFAULT_PORT);
            this.sessions = new List<Session>();
        }

        /// <summary>
        /// Gets or sets the local end point on which the server will listen.
        /// Has to be an IPv4 endpoint.
        /// The default value is IPAdress.Any and port 21, except on WinCE,
        /// where the first non-loopback IPv4 address will be used.
        /// </summary>
        public IPEndPoint LocalEndPoint
        {
            get { return endpoint; }
            set { endpoint = value; }
        }

        /// <summary>
        /// Gets or sets the local IP address on which the server will listen.
        /// Has to be an IPv4 address.
        /// If none is set, IPAddress.Any will be used, except on WinCE,
        /// where the first non-loopback IPv4 address will be used.
        /// </summary>
        public IPAddress LocalAddress
        {
            get { return endpoint.Address; }
            set { endpoint.Address = value; }
        }

        /// <summary>
        /// Gets or sets the local port on which the server will listen.
        /// The default value is 21. Note that on Linux, only root can open ports < 1024.
        /// </summary>
        public int LocalPort
        {
            get { return endpoint.Port; }
            set { endpoint.Port = value; }
        }

        /// <summary>
        /// Gets or sets the size of the send/receive buffer to be used by each session/connection.
        /// The default value is 64k.
        /// </summary>
        public int BufferSize
        {
            get { return bufferSize; }
            set { bufferSize = value; }
        }

        /// <summary>
        /// Gets or sets the auth handler that is used to check user credentials.
        /// If none is set, a DefaultAuthHandler will be created when the server starts.
        /// </summary>
        public IAuthHandler AuthHandler
        {
            get { return authHandler; }
            set { authHandler = value; }
        }

        /// <summary>
        /// Gets or sets the file system handler that implements file system access for FTP commands.
        /// If none is set, a DefaultFileSystemHandler is created when the server starts.
        /// </summary>
        public IFileSystemHandler FileSystemHandler
        {
            get { return fsHandler; }
            set { fsHandler = value; }
        }

        /// <summary>
        /// Gets or sets the log handler. Can be null to disable logging.
        /// The default value is null.
        /// </summary>
        public ILogHandler LogHandler
        {
            get { return logHandler; }
            set { logHandler = value; }
        }

        /// <summary>
        /// Run the server. The method will not return until Stop() is called.
        /// </summary>
        public void Run()
        {
            //if (authHandler == null)
            //    authHandler = new DefaultAuthHandler();

            //if (fsHandler == null)
            //    fsHandler = new DefaultFileSystemHandler();

            if (socket == null)
                socket = new TcpListener(endpoint);

            socket.Start();

            // listen for new connections
            try {
                while (true)
                {
                    Socket peer = socket.AcceptSocket();

                    IPEndPoint peerPort = (IPEndPoint) peer.RemoteEndPoint;
                    Session session = new Session(peer, bufferSize,
                                                  authHandler.Clone(peerPort),
                                                  fsHandler.Clone(peerPort),
                                                  logHandler.Clone(peerPort));

                    session.Start();
                    sessions.Add(session);

                    // purge old sessions
                    for (int i = sessions.Count - 1; i >= 0; --i)
                    {
                        if (!sessions[i].IsOpen) {
                            sessions.RemoveAt(i);
                            --i;
                        }
                    }
                }
            } catch (SocketException) {
                // ignore, Stop() will probably cause this exception
            } finally {
                // close all running connections
                foreach (Session s in sessions) {
                    s.Stop();
                }
            }
        }

        /// <summary>
        /// Stop the server.
        /// </summary>
        public void Stop()
        {
            if (socket == null) return;
            socket.Stop();
        }

        /// <summary>
        /// Get the default address, which is IPAddress.Any everywhere except on WinCE,
        /// where all local addresses are enumerated and the first non-loopback IP is used.
        /// </summary>
        private IPAddress GetDefaultAddress()
        {
            // on WinCE, 0.0.0.0 does not work because for accepted sockets,
            // LocalEndPoint would also say 0.0.0.0 instead of the real IP
#if WindowsCE
            IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
            IPAddress bindIp = IPAddress.Loopback;
            foreach (IPAddress ip in host.AddressList) {
                if (ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip)) {
                    return ip;
                }
            }

            return IPAddress.Loopback;
#else
            return IPAddress.Any;
#endif
        }
    }
}