FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
NakovForwardServer/NakovForwardServer.java at master · nakov/NakovForwardServer · GitHub
nakov
/
NakovForwardServer
Public
Notifications
You must be signed in to change notification settings
Fork
14
Star
51
Code
Issues
0
Pull requests
0
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
NakovForwardServer
/
NakovForwardServer.java
Copy path
More file actions
More file actions
Latest commit
History
History
History
269 lines (249 loc) · 11.1 KB
Breadcrumbs
NakovForwardServer
/
NakovForwardServer.java
Copy path
File metadata and controls
269 lines (249 loc) · 11.1 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/**
* Nakov TCP Socket Forward Server - freeware
* Version 1.0 - March, 2002
* (c) 2001 by Svetlin Nakov - http://www.nakov.com
*
* Short decription: Nakov Forward Server is designed to forward (redirect) TCP
* connections from a client to a server choosen from a servers list. When a client
* is connected to Nakov Forward Server, a new connection is opened to some of the
* specified destination servers and all the traffic from destination server to
* Nakov Forward Server is redirected to the client and also all the traffic from
* the client to Nakov Forward Server is redirected to destination server. That
* way Nakov Forward Server makes transparent redirection of TCP connections.
* The data transfer schema is the following:
*
* CLIENT <--> NAKOV_FORWARD_SERVER <--> DESTINATION_SERVER
*
* Clients and Destination Servers communicate only with Nakov Forward Server.
*
* Nakov Forward Server supports failt tolerance. When some of the servers in the
* list fail to respond to TCP connect request (dead server), Nakov Forward Server
* tries the next server in the list until it finds alive server. All dead servers
* are checked if they are alive through some time interval and when some server
* becomes available, it is added to alive list. When no server is alive, no
* connection will be established.
*
* Nakov Forward Server supports also load balancing features. If load balancing
* is enabled, when a client connection is accepted, Nakov Forward Server will
* redirect the client to the least loaded server from the servers list. We consider
* the server which hast minimal alive connections established by Nakov Forward
* Server is least loaded.
*
* What we gain when we use Nakov Proxy Server?
* - Destination server does not know the real IP of the client. It thinks
* that the IP of Nakov Forward Server is its client. Thus we can use a server
* licensed for one IP address on several machines simultaneously.
* - Nakov Forward Server can run on a port number that is allowed by the
* firewall and forward to a port number that is not allowed by firewall. Thus,
* started on a server in a local network, it can give access to some disabled
* by the firewall services.
* - Nakov Forward Server can give access to multiple clients to some service
* that is allowed only for some fixed IP address when started on the machine
* with this IP.
* - Fault Tolerance (failover) of Nakov Forward Server helps to avoid faults
* when some of the servers die. Of course there is special hardware for this, but
* it has high price. Instead you can use Nakov Forward Server (that is free).
* If you setup several Nakov Forward Servers configured to use the same set of
* destination servers and if you configure your routers to use redirect traffic
* to both servers, you will obtain a stable fault tolerance system. In such a
* system you have guarantee that crash of any of the servers (including some of
* the Nakov Forward Servers) will not stop the service that these servers provide.
* Of course the destination servers should run in a cluster and replicate their
* sessions.
* - Load balancing helps to avoid overloading of the servers by distributing
* the clients between them. Of course this should be done by special hardware
* called "load balancer", but if we don't have such hardware, we can still use
* this technology. When we use load balancing, all the servers in the list should
* be running in a cluster and there should be no matter what of the servers the
* client is connected to. The servers should communicate each other and replicate
* their session data.
*
* NakovForwardServer.properties configuration file contains all the settings of
* Nakov Forward Server. The only mandatory field is "Servers"
* Destination servers should be in following format:
* Servers = server1:port1, server2:port2, server3:port3, ...
* For example:
* Servers = 192.168.0.22:80, rakiya:80, 192.168.0.23:80, www.nakov.com:80
* Nakov Forward Server listening port should be in format:
* ListeningPort = some_port (in range 1-65535)
* Using load balancing algorithm is specified by following line:
* LoadBalancing = Yes/No
* Check alive interval through which all dead threads should be re-checked if
* they are alive is specified by following line:
* CheckAliveInterval = time_interval (in milliseconds)
*/
import
java
.
util
.
ArrayList
;
import
java
.
net
.
ServerSocket
;
import
java
.
net
.
Socket
;
import
java
.
net
.
InetAddress
;
import
java
.
io
.
IOException
;
import
java
.
io
.
FileInputStream
;
import
java
.
util
.
Properties
;
import
java
.
util
.
StringTokenizer
;
public
class
NakovForwardServer
{
private
static
final
boolean
ENABLE_LOGGING
=
true
;
public
static
final
String
SETTINGS_FILE_NAME
=
"NakovForwardServer.properties"
;
private
ServerDescription
[]
mServersList
=
null
;
private
int
mListeningTcpPort
=
2001
;
private
boolean
mUseLoadBalancingAlgorithm
=
true
;
private
long
mCheckAliveIntervalMs
=
5
*
1000
;
/**
* ServerDescription descripts a server (server hostname/IP, server port,
* is the server alive at last check, how many clients are connected to it, etc.)
*/
class
ServerDescription
{
public
String
host
;
public
int
port
;
public
int
clientsConectedCount
=
0
;
public
boolean
isAlive
=
true
;
public
ServerDescription
(
String
host
,
int
port
)
{
this
.
host
=
host
;
this
.
port
=
port
;
}
}
/**
* @return an array of ServerDescription - all destination servers.
*/
public
ServerDescription
[]
getServersList
()
{
return
mServersList
;
}
/**
* @return the time interval (in milliseconds) through which all dead servers
* should be re-checked if they are alive (a server is alive if accepts
* client connections on the specified port, otherwise is dead).
*/
public
long
getCheckAliveIntervalMs
()
{
return
mCheckAliveIntervalMs
;
}
/**
* @return true if load balancing algorithm is enabled.
*/
public
boolean
isLoadBalancingEnabled
()
{
return
mUseLoadBalancingAlgorithm
;
}
/**
* Reads the Nakov Forward Server configuration file "NakovForwardServer.properties"
* and load user preferences. This method is called once during the server startup.
*/
public
void
readSettings
()
throws
Exception
{
// Read properties file in a Property object
Properties
props
=
new
Properties
();
props
.
load
(
new
FileInputStream
(
SETTINGS_FILE_NAME
));
// Read and parse the server list
String
serversProperty
=
props
.
getProperty
(
"Servers"
);
if
(
serversProperty
==
null
)
throw
new
Exception
(
"The server list can not be empty."
);
try
{
ArrayList
servers
=
new
ArrayList
();
StringTokenizer
stServers
=
new
StringTokenizer
(
serversProperty
,
","
);
while
(
stServers
.
hasMoreTokens
()) {
String
serverAndPort
=
stServers
.
nextToken
().
trim
();
StringTokenizer
stServerPort
=
new
StringTokenizer
(
serverAndPort
,
": "
);
String
host
=
stServerPort
.
nextToken
();
int
port
=
Integer
.
parseInt
(
stServerPort
.
nextToken
());
servers
.
add
(
new
ServerDescription
(
host
,
port
));
}
mServersList
= (
ServerDescription
[])
servers
.
toArray
(
new
ServerDescription
[] {});
}
catch
(
Exception
e
) {
throw
new
Exception
(
"Invalid server list format : "
+
serversProperty
);
}
if
(
mServersList
.
length
==
0
)
throw
new
Exception
(
"The server list can not be empty."
);
// Read server's listening port number
try
{
mListeningTcpPort
=
Integer
.
parseInt
(
props
.
getProperty
(
"ListeningPort"
));
}
catch
(
Exception
e
) {
log
(
"Server listening port not specified. Using default port : "
+
mListeningTcpPort
);
}
// Read load balancing property
try
{
String
loadBalancing
=
props
.
getProperty
(
"LoadBalancing"
).
toLowerCase
();
mUseLoadBalancingAlgorithm
= (
loadBalancing
.
equals
(
"yes"
) ||
loadBalancing
.
equals
(
"true"
) ||
loadBalancing
.
equals
(
"1"
) ||
loadBalancing
.
equals
(
"enable"
) ||
loadBalancing
.
equals
(
"enabled"
));
}
catch
(
Exception
e
) {
log
(
"LoadBalancing property is not specified. Using default value : "
+
mUseLoadBalancingAlgorithm
);
}
// Read the check alive interval
try
{
mCheckAliveIntervalMs
=
Integer
.
parseInt
(
props
.
getProperty
(
"CheckAliveInterval"
));
}
catch
(
Exception
e
) {
log
(
"Check alive interval is not specified. Using default value : "
+
mCheckAliveIntervalMs
+
" ms."
);
}
}
/**
* Starts a thread that re-checks all dead threads if they are alive
* through mCheckAliveIntervalMs millisoconds
*/
private
void
startCheckAliveThread
()
{
CheckAliveThread
checkAliveThread
=
new
CheckAliveThread
(
this
);
checkAliveThread
.
setDaemon
(
true
);
checkAliveThread
.
start
();
}
/**
* Starts the forward server - binds on a given port and starts serving
*/
public
void
startForwardServer
()
throws
Exception
{
// Bind server on given TCP port
ServerSocket
serverSocket
;
try
{
serverSocket
=
new
ServerSocket
(
mListeningTcpPort
);
}
catch
(
IOException
ioe
) {
throw
new
IOException
(
"Unable to bind to port "
+
mListeningTcpPort
);
}
log
(
"Nakov Forward Server started on TCP port "
+
mListeningTcpPort
+
"."
);
log
(
"All TCP connections to "
+
InetAddress
.
getLocalHost
().
getHostAddress
() +
":"
+
mListeningTcpPort
+
" will be forwarded to the following servers:"
);
for
(
int
i
=
0
;
i
<
mServersList
.
length
;
i
++) {
log
(
" "
+
mServersList
[
i
].
host
+
":"
+
mServersList
[
i
].
port
);
}
log
(
"Load balancing algorithm is "
+ (
mUseLoadBalancingAlgorithm
?
"ENABLED."
:
"DISABLED."
));
// Accept client connections and process them until stopped
while
(
true
) {
try
{
Socket
clientSocket
=
serverSocket
.
accept
();
String
clientHostPort
=
clientSocket
.
getInetAddress
().
getHostAddress
() +
":"
+
clientSocket
.
getPort
();
log
(
"Accepted client from "
+
clientHostPort
);
ForwardServerClientThread
forwardThread
=
new
ForwardServerClientThread
(
this
,
clientSocket
);
forwardThread
.
start
();
}
catch
(
Exception
e
) {
throw
new
Exception
(
"Unexpected error.
\n
"
+
e
.
toString
());
}
}
}
/**
* Prints given log message on the standart output if logging is enabled,
* otherwise ignores it
*/
public
void
log
(
String
aMessage
)
{
if
(
ENABLE_LOGGING
)
System
.
out
.
println
(
aMessage
);
}
/**
* Program entry point. Reads settings, starts check-alive thread and
* the forward server
*/
public
static
void
main
(
String
[]
aArgs
)
{
NakovForwardServer
srv
=
new
NakovForwardServer
();
try
{
srv
.
readSettings
();
srv
.
startCheckAliveThread
();
srv
.
startForwardServer
();
}
catch
(
Exception
e
) {
e
.
printStackTrace
();
}
}
}
Back
|
FazBrowse Home
|
New Git URL