📄 main.cpp
字号:
//rDUN server version 0.1
////Copyright (C) Robert Merrison 2002-03
//
////This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
////as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
////This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
////warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
////You should have received a copy of the GNU General Public License along with this program; if not, write to the
////Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "main.h"
#define MAX_CLIENTS 4
#define PROTOCOL_VERSION 1
#define STATE_IDLE 0
#define STATE_ASKAUTH 1
#define STATE_WAITAUTH 2
#define STATE_GOODPASS 3
#define STATE_BADPASS 4
#define STATE_CONNECTING 5
#define STATE_CONNECTED 6
#define STATE_DISCONNECTING 7
#define STATE_DISCONNECTED 8
#define STATE_USERDISCONNECTING 9
#define STATE_USERDISCONNECTED 10
#define STATE_WAITPROTOCOL 11
#define STATE_GOODPROTOCOL 12
#define STATE_BADPROTOCOL 13
struct client{
int socket;
int state;
int ping_response_time;
char recv_buffer[256];
};
int listen_socket;
client clients[MAX_CLIENTS];
fd_set listen_set;
fd_set write_set;
fd_set error_set;
fd_set base_listen_set;
fd_set base_write_set;
fd_set base_error_set;
char auth_code[128];
cfg_ptr config;
time_engine timer;
debug_engine debug;
int connection_state;
FILE* wvdial_pipe;
bool awaiting_ping;
void closedown( int );
int get_free_socket();
void process_client_sets();
void write_data( int client );
void read_data( int client );
int get_highest_descriptor();
void process_recv_buffer( int client );
int send_data( int client, char* buffer );
void process_wvdial_pipe();
void set_global_state( int state );
int main()
{
signal( SIGHUP, closedown ); //Call closedown() on SIGHUP
signal( SIGTERM, closedown );
signal(SIGCHLD,SIG_IGN); /* ignore child */
signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
if( !debug.init( DBLEVEL_HIGH, "debug2.log", &timer )){
return 0;
}
config = cfgParse( "rDUNd.conf" );
connection_state = STATE_DISCONNECTED;
//Set the connect password
memset( auth_code, 0, sizeof( auth_code ));
strcpy( auth_code, cfgGetString( config, "MAIN", "PASSWORD", "" ));
printf( "%s\n", auth_code );
//Clear out the client socket array
for( int i = 0; i < MAX_CLIENTS; i++ ){
clients[i].socket = -1;
memset( clients[i].recv_buffer, 0, sizeof( clients[i].recv_buffer ));
}
//Create the socket to listen on
listen_socket = socket( AF_INET, SOCK_STREAM, 0 );
if( listen_socket == -1 ){
debug.log_message( MSG_CRITICAL, "Error creating listen socket" );
closedown( 0 );
}
//Set up address to bind listen socket to
sockaddr_in listen_addr;
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = htons( cfgGetInt( config, "MAIN", "LISTEN_PORT", 2244 ));
listen_addr.sin_addr.s_addr = INADDR_ANY;
memset( &( listen_addr.sin_zero ), '\0', 8 );
//Bind the listen socket
if( bind( listen_socket, ( sockaddr* )&listen_addr, sizeof( sockaddr )) == -1 ){
debug.log_message( MSG_CRITICAL, "Error binding listen socket" );
closedown( 0 );
}
linger lingerSettings;
lingerSettings.l_onoff = 1;
lingerSettings.l_linger = 0;
setsockopt( listen_socket, SOL_SOCKET, SO_LINGER, &lingerSettings, sizeof( lingerSettings ));
BOOL reuseAddrSetting = TRUE;
setsockopt( listen_socket, SOL_SOCKET, SO_REUSEADDR, &reuseAddrSetting, sizeof( reuseAddrSetting ));
//Start listening on the listen socket
if( listen( listen_socket, 2 ) == -1 ){
//Error message here
closedown( 0 );
}
//Set up the listen set
FD_ZERO( &listen_set );
FD_SET( listen_socket, &listen_set );
//Set up the write and error sets
FD_ZERO( &write_set );
FD_ZERO( &error_set );
timeval select_timeout;
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 0;
FD_ZERO( &base_listen_set );
memcpy( &base_listen_set, &listen_set, sizeof( base_listen_set ));
FD_ZERO( &base_write_set );
memcpy( &base_write_set, &write_set, sizeof( base_write_set ));
FD_ZERO( &base_error_set );
memcpy( &base_error_set, &error_set, sizeof( base_error_set ));
if(fork()) exit(0);
//Main program loop
while( 1 ){
memcpy( &listen_set, &base_listen_set, sizeof( base_listen_set ));
memcpy( &write_set, &base_write_set, sizeof( base_write_set ));
memcpy( &error_set, &base_error_set, sizeof( base_error_set ));
select( get_highest_descriptor()+1, &listen_set, &write_set, &error_set, &select_timeout );
if( FD_ISSET( listen_socket, &listen_set )){ //Check for a new connection waiting
int free_socket = get_free_socket();
if( free_socket == -1 ){ //If there are no free client sockets
debug.log_message( MSG_STATUS, "Full, dropping new client" );
int temp_socket = accept( listen_socket, NULL, NULL );
send( temp_socket, "FULL\r\n", 4, 0 );
close( temp_socket );
}
else{ //Otherwise, accept the new client
clients[free_socket].socket = accept( listen_socket, NULL, NULL );
if( clients[free_socket].socket == -1 ){
debug.log_message( MSG_ERROR, "Error accepting new client in slot %d\n", free_socket );
}
clients[free_socket].state = STATE_ASKAUTH;
FD_SET( clients[free_socket].socket, &base_listen_set );
FD_SET( clients[free_socket].socket, &base_write_set );
FD_SET( clients[free_socket].socket, &base_error_set );
linger lingerSettings;
lingerSettings.l_onoff = 1;
lingerSettings.l_linger = 0;
setsockopt( clients[free_socket].socket, SOL_SOCKET, SO_LINGER, &lingerSettings, sizeof( lingerSettings ));
BOOL reuseAddrSetting = TRUE;
setsockopt( clients[free_socket].socket, SOL_SOCKET, SO_REUSEADDR, &reuseAddrSetting, sizeof( reuseAddrSetting ));
debug.log_message( MSG_STATUS, "Accepted new client in slot %d", free_socket );
}
}
process_client_sets();
process_wvdial_pipe();
}
closedown( 0 );
return 1;
}
void process_client_sets()
{
for( int i=0; i<MAX_CLIENTS; i++ ){
if( clients[i].socket == -1 ){
continue;
}
if( FD_ISSET( clients[i].socket, &listen_set )){
read_data( i );
}
//if( FD_ISSET( clients[i].socket, &write_set )){
write_data( i );
//}
if( FD_ISSET( clients[i].socket, &error_set )){
debug.log_message( MSG_STATUS, "Client %d in error set, dropping", i );
shutdown( clients[i].socket, 2 );
close( clients[i].socket );
FD_CLR( clients[i].socket, &base_listen_set );
FD_CLR( clients[i].socket, &base_write_set );
FD_CLR( clients[i].socket, &base_error_set );
memset( clients[i].recv_buffer, 0, sizeof( clients[i].recv_buffer ));
clients[i].socket = -1;
return;
}
}
}
void process_wvdial_pipe()
{
if( wvdial_pipe == NULL ){
return;
}
char wvbuffer[256];
memset( wvbuffer, 0, sizeof( wvbuffer ));
if( fgets( wvbuffer, (int)sizeof( wvbuffer ), wvdial_pipe )){
if( strstr( wvbuffer, "Disconnect" )){
debug.log_message( MSG_STATUS, "WVdial disconnect" );
fclose( wvdial_pipe );
wvdial_pipe = NULL;
system( "killall wvdial" );
if( connection_state == STATE_USERDISCONNECTING ){
set_global_state( STATE_USERDISCONNECTED );
connection_state = STATE_USERDISCONNECTED;
}
else{
set_global_state( STATE_DISCONNECTED );
connection_state = STATE_DISCONNECTED;
}
return;
}
if( strstr( wvbuffer, "Starting pppd" )){
debug.log_message( MSG_STATUS, "WVdial connect" );
set_global_state( STATE_CONNECTED );
connection_state = STATE_CONNECTED;
return;
}
}
return;
}
void read_data( int client )
{
char data;
if( recv( clients[client].socket, &data, 1, 0 ) == 0 ){
FD_SET( clients[client].socket, &error_set );
debug.log_message( MSG_STATUS, "Error on client %d, socket closed", client );
return;
}
if( strlen( clients[client].recv_buffer )+1 >= sizeof( clients[client].recv_buffer )){
debug.log_message( MSG_NOTICE, "Buffer overflow on client %d, dropping\n", client );
FD_SET( clients[client].socket, &error_set );
return;
}
if( data == '\r' ){
return;
}
if( data == '\n' ){
process_recv_buffer( client );
memset( clients[client].recv_buffer, 0, sizeof( clients[client].recv_buffer ));
return;
}
printf( "Added %c, ", data );
clients[client].recv_buffer[ strlen( clients[client].recv_buffer )] = data;
printf( "New buffer: %s\n", clients[client].recv_buffer );
return;
}
void write_data( int client )
{
if( clients[client].state == STATE_ASKAUTH ){
send_data( client, "AUTH\r\n" );
clients[client].state = STATE_WAITAUTH;
return;
}
if( clients[client].state == STATE_GOODPASS ){
send_data( client, "OK\r\n" );
clients[client].state = STATE_WAITPROTOCOL;
return;
}
if( clients[client].state == STATE_GOODPROTOCOL ){
send_data( client, "GOODPROTOCOL\r\n" );
clients[client].state = connection_state;
return;
}
if( clients[client].state == STATE_BADPROTOCOL ){
send_data( client, "BADPROTOCOL\r\n" );
clients[client].state = STATE_WAITPROTOCOL;
FD_SET( clients[client].socket, &error_set );
}
if( clients[client].state == STATE_BADPASS ){
send_data( client, "BADPASS\r\n" );
clients[client].state = STATE_WAITAUTH;
return;
}
if( clients[client].state == STATE_CONNECTING ){
send_data( client, "CONNECTING\r\n");
clients[client].state = STATE_IDLE;
return;
}
if( clients[client].state == STATE_CONNECTED ){
send_data( client, "CONNECTED\r\n" );
clients[client].state = STATE_IDLE;
return;
}
if( clients[client].state == STATE_DISCONNECTING ){
send_data( client, "DISCONNECTING\r\n" );
clients[client].state = STATE_IDLE;
return;
}
if( clients[client].state == STATE_DISCONNECTED ){
send_data( client, "DISCONNECTED\r\n" );
clients[client].state = STATE_IDLE;
return;
}
if( clients[client].state == STATE_USERDISCONNECTING ){
send_data( client, "USERDISCONNECTING\r\n" );
clients[client].state = STATE_IDLE;
return;
}
if( clients[client].state == STATE_USERDISCONNECTED ){
send_data( client, "USERDISCONNECTED\r\n" );
clients[client].state = STATE_IDLE;
return;
}
return;
}
void process_recv_buffer( int client )
{
printf( "Processing: %s on client %d\n", clients[client].recv_buffer, client );
if( clients[client].state == STATE_WAITAUTH ){
if( strcmp( clients[client].recv_buffer, auth_code ) == 0 ){
clients[client].state = STATE_GOODPASS;
return;
}
else{
clients[client].state = STATE_BADPASS;
return;
}
}
if( clients[client].state == STATE_WAITPROTOCOL ){
if( strncasecmp( clients[client].recv_buffer, "PROTOCOL", 8 ) != 0 ){
return;
}
int proto_version = 0;
sscanf( clients[client].recv_buffer, "PROTOCOL %d", &proto_version );
printf( "Protocol: %d\n", proto_version );
if( proto_version < PROTOCOL_VERSION ){
clients[client].state = STATE_BADPROTOCOL;
return;
}
clients[client].state = STATE_GOODPROTOCOL;
return;
}
if( strcasecmp( clients[client].recv_buffer, "CONNECT" ) == 0 ){
if( connection_state == STATE_CONNECTED ){
return;
}
if( wvdial_pipe ){
fclose( wvdial_pipe );
}
system( "rm -f wv_out" );
system( "touch wv_out" );
wvdial_pipe = fopen( "wv_out", "r" );
system( "./start_wvdial" );
debug.log_message( MSG_STATUS, "Connecting" );
connection_state = STATE_CONNECTING;
set_global_state( STATE_CONNECTING );
return;
}
if( strcasecmp( clients[client].recv_buffer, "DISCONNECT" ) == 0 ){
debug.log_message( MSG_STATUS, "Disconnecting" );
system( "killall wvdial" );
connection_state = STATE_USERDISCONNECTING;
set_global_state( STATE_USERDISCONNECTING );
return;
}
return;
}
int send_data( int client, char* data )
{
int ret = send( clients[client].socket, data, strlen( data ), 0 );
debug.log_message( MSG_STATUS, "Sending %s to client %d", data, client );
return ret;
}
void set_global_state( int state )
{
for( int i=0; i<MAX_CLIENTS; i++ ){
clients[i].state = state;
}
return;
}
void closedown( int )
{
debug.log_message( MSG_STATUS, "Beginning closedown" );
close( listen_socket );
for( int i=0; i < MAX_CLIENTS; i++ ){
if( clients[i].socket != -1 ){
debug.log_message( MSG_STATUS, "Killing client %d", i );
close( clients[i].socket );
}
}
exit( 1 );
}
int get_free_socket()
{
for( int i=0; i < MAX_CLIENTS; i++ ){
if( clients[i].socket == -1 ){
return i;
}
}
return -1;
}
int get_highest_descriptor()
{
int highest = listen_socket;
for( int i=0; i < MAX_CLIENTS; i++ ){
if( clients[i].socket > highest ){
highest = clients[i].socket;
}
}
return highest;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -