2014-07-31 18:55:42 +00:00
// Copyright (c) 2014- PPSSPP Project.
// 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, version 2.0 or later versions.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// proAdhocServer
// This is a direct port of Coldbird's code from http://code.google.com/p/aemu/
// All credit goes to him!
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <signal.h>
# if !defined(__APPLE__)
2014-08-19 14:29:03 +00:00
# include <stdlib.h>
2014-07-31 18:55:42 +00:00
# endif
# include <sys/types.h>
// Net stuff
# ifdef _XBOX
# include <winsockx.h>
typedef int socklen_t ;
# elif defined(_MSC_VER)
# include <WS2tcpip.h>
# else
# include <sys/socket.h>
# include <netinet/in.h>
# endif
# include <fcntl.h>
# include <errno.h>
//#include <sqlite3.h>
# include "Core/Core.h"
# include "Core/HLE/proAdhocServer.h"
// User Count
uint32_t _db_user_count = 0 ;
// User Database
SceNetAdhocctlUserNode * _db_user = NULL ;
// Game Database
SceNetAdhocctlGameNode * _db_game = NULL ;
// Server Status
//int _status = 0;
bool adhocServerRunning = false ;
std : : thread adhocServerThread ;
2014-08-05 12:05:08 +00:00
std : : vector < db_crosslink > crosslinks ;
std : : vector < db_productid > productids ;
2014-07-31 18:55:42 +00:00
// Function Prototypes
const char * strcpyxml ( char * out , const char * in , uint32_t size ) ;
// Function Prototypes
void interrupt ( int sig ) ;
void enable_address_reuse ( int fd ) ;
void change_blocking_mode ( int fd , int nonblocking ) ;
int create_listen_socket ( uint16_t port ) ;
int server_loop ( int server ) ;
2014-08-05 12:05:08 +00:00
void __AdhocServerInit ( ) {
// I'm too lazy to copy the whole list here, we should read these from database.db
2014-08-11 16:06:09 +00:00
crosslinks . push_back ( db_crosslink { " ULES01408 " , " ULUS10511 " } ) ;
2014-08-05 12:05:08 +00:00
crosslinks . push_back ( db_crosslink { " NPJH50263 " , " ULUS10511 " } ) ;
productids . push_back ( db_productid { " ULUS10511 " , " Ace Combat X2 - Joint Assault " } ) ;
productids . push_back ( db_productid { " NPUH10023 " , " Armored Core 3 Portable " } ) ;
}
2014-07-31 18:55:42 +00:00
/**
* Login User into Database ( Stream )
* @ param fd Socket
* @ param ip IP Address ( Network Order )
*/
void login_user_stream ( int fd , uint32_t ip )
{
// Enough Space available
if ( _db_user_count < SERVER_USER_MAXIMUM )
{
// Check IP Duplication
SceNetAdhocctlUserNode * u = _db_user ;
while ( u ! = NULL & & u - > resolver . ip ! = ip ) u = u - > next ;
if ( u ! = NULL ) { // IP Already existed
uint8_t * ip4 = ( uint8_t * ) & u - > resolver . ip ;
INFO_LOG ( SCENET , " AdhocServer: Already Existing IP: %u.%u.%u.%u \n " , ip4 [ 0 ] , ip4 [ 1 ] , ip4 [ 2 ] , ip4 [ 3 ] ) ;
}
// Unique IP Address
else //if(u == NULL)
{
// Allocate User Node Memory
SceNetAdhocctlUserNode * user = ( SceNetAdhocctlUserNode * ) malloc ( sizeof ( SceNetAdhocctlUserNode ) ) ;
// Allocated User Node Memory
if ( user ! = NULL )
{
// Clear Memory
memset ( user , 0 , sizeof ( SceNetAdhocctlUserNode ) ) ;
// Save Socket
user - > stream = fd ;
// Save IP
user - > resolver . ip = ip ;
// Link into User List
user - > next = _db_user ;
if ( _db_user ! = NULL ) _db_user - > prev = user ;
_db_user = user ;
// Initialize Death Clock
user - > last_recv = time ( NULL ) ;
// Notify User
uint8_t * ipa = ( uint8_t * ) & user - > resolver . ip ;
INFO_LOG ( SCENET , " AdhocServer: New Connection from %u.%u.%u.%u " , ipa [ 0 ] , ipa [ 1 ] , ipa [ 2 ] , ipa [ 3 ] ) ;
// Fix User Counter
_db_user_count + + ;
// Update Status Log
update_status ( ) ;
// Exit Function
return ;
}
}
}
// Duplicate IP, Allocation Error or not enough space - Close Stream
closesocket ( fd ) ;
}
/**
* Login User into Database ( Login Data )
* @ param user User Node
* @ param data Login Packet
*/
void login_user_data ( SceNetAdhocctlUserNode * user , SceNetAdhocctlLoginPacketC2S * data )
{
// Product Code Check
int valid_product_code = 1 ;
// Iterate Characters
int i = 0 ; for ( ; i < PRODUCT_CODE_LENGTH & & valid_product_code = = 1 ; i + + )
{
// Valid Characters
if ( ! ( ( data - > game . data [ i ] > = ' A ' & & data - > game . data [ i ] < = ' Z ' ) | | ( data - > game . data [ i ] > = ' 0 ' & & data - > game . data [ i ] < = ' 9 ' ) ) ) valid_product_code = 0 ;
}
// Valid Packet Data
if ( valid_product_code = = 1 & & memcmp ( & data - > mac , " \xFF \xFF \xFF \xFF \xFF \xFF " , sizeof ( data - > mac ) ) ! = 0 & & memcmp ( & data - > mac , " \x00 \x00 \x00 \x00 \x00 \x00 " , sizeof ( data - > mac ) ) ! = 0 & & data - > name . data [ 0 ] ! = 0 )
{
// Game Product Override
game_product_override ( & data - > game ) ;
// Find existing Game
SceNetAdhocctlGameNode * game = _db_game ;
while ( game ! = NULL & & strncmp ( game - > game . data , data - > game . data , PRODUCT_CODE_LENGTH ) ! = 0 ) game = game - > next ;
// Game not found
if ( game = = NULL )
{
// Allocate Game Node Memory
game = ( SceNetAdhocctlGameNode * ) malloc ( sizeof ( SceNetAdhocctlGameNode ) ) ;
// Allocated Game Node Memory
if ( game ! = NULL )
{
// Clear Memory
memset ( game , 0 , sizeof ( SceNetAdhocctlGameNode ) ) ;
// Save Game Product ID
game - > game = data - > game ;
// Link into Game List
game - > next = _db_game ;
if ( _db_game ! = NULL ) _db_game - > prev = game ;
_db_game = game ;
}
}
// Game now available
if ( game ! = NULL )
{
// Save MAC
user - > resolver . mac = data - > mac ;
// Save Nickname
user - > resolver . name = data - > name ;
// Increase Player Count in Game Node
game - > playercount + + ;
// Link Game to Player
user - > game = game ;
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , game - > game . data , PRODUCT_CODE_LENGTH ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) started playing %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr ) ;
// Update Status Log
update_status ( ) ;
// Leave Function
return ;
}
}
// Invalid Packet Data
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
INFO_LOG ( SCENET , " AdhocServer: Invalid Login Packet Contents from %u.%u.%u.%u " , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] ) ;
}
// Logout User - Out of Memory or Invalid Arguments
logout_user ( user ) ;
}
/**
* Logout User from Database
* @ param user User Node
*/
void logout_user ( SceNetAdhocctlUserNode * user )
{
// Disconnect from Group
if ( user - > group ! = NULL ) disconnect_user ( user ) ;
// Unlink Leftside (Beginning)
if ( user - > prev = = NULL ) _db_user = user - > next ;
// Unlink Leftside (Other)
else user - > prev - > next = user - > next ;
// Unlink Rightside
if ( user - > next ! = NULL ) user - > next - > prev = user - > prev ;
// Close Stream
closesocket ( user - > stream ) ;
// Playing User
if ( user - > game ! = NULL )
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) stopped playing %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr ) ;
// Fix Game Player Count
user - > game - > playercount - - ;
// Empty Game Node
if ( user - > game - > playercount = = 0 )
{
// Unlink Leftside (Beginning)
if ( user - > game - > prev = = NULL ) _db_game = user - > game - > next ;
// Unlink Leftside (Other)
else user - > game - > prev - > next = user - > game - > next ;
// Unlink Rightside
if ( user - > game - > next ! = NULL ) user - > game - > next - > prev = user - > game - > prev ;
// Free Game Node Memory
free ( user - > game ) ;
}
}
// Unidentified User
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
INFO_LOG ( SCENET , " AdhocServer: Dropped Connection to %u.%u.%u.%u " , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] ) ;
}
// Free Memory
free ( user ) ;
// Fix User Counter
_db_user_count - - ;
// Update Status Log
update_status ( ) ;
}
/**
* Free Database Memory
*/
void free_database ( void )
{
// There are users playing
if ( _db_user_count > 0 )
{
// Send Shutdown Notice
spread_message ( NULL , SERVER_SHUTDOWN_MESSAGE ) ;
}
// Iterate Users for Deletion
SceNetAdhocctlUserNode * user = _db_user ;
while ( user ! = NULL )
{
// Next User (for safe delete)
SceNetAdhocctlUserNode * next = user - > next ;
// Logout User
logout_user ( user ) ;
// Move Pointer
user = next ;
}
}
/**
* Connect User to Game Group
* @ param user User Node
* @ param group Group Name
*/
void connect_user ( SceNetAdhocctlUserNode * user , SceNetAdhocctlGroupName * group )
{
// Group Name Check
int valid_group_name = 1 ;
{
// Iterate Characters
int i = 0 ; for ( ; i < ADHOCCTL_GROUPNAME_LEN & & valid_group_name = = 1 ; i + + )
{
// End of Name
if ( group - > data [ i ] = = 0 ) break ;
// A - Z
if ( group - > data [ i ] > = ' A ' & & group - > data [ i ] < = ' Z ' ) continue ;
// a - z
if ( group - > data [ i ] > = ' a ' & & group - > data [ i ] < = ' z ' ) continue ;
// 0 - 9
if ( group - > data [ i ] > = ' 0 ' & & group - > data [ i ] < = ' 9 ' ) continue ;
// Invalid Symbol
valid_group_name = 0 ;
}
}
// Valid Group Name
if ( valid_group_name = = 1 )
{
// User is disconnected
if ( user - > group = = NULL )
{
// Find Group in Game Node
SceNetAdhocctlGroupNode * g = user - > game - > group ;
while ( g ! = NULL & & strncmp ( ( char * ) g - > group . data , ( char * ) group - > data , ADHOCCTL_GROUPNAME_LEN ) ! = 0 ) g = g - > next ;
// BSSID Packet
SceNetAdhocctlConnectBSSIDPacketS2C bssid ;
// Set BSSID Opcode
bssid . base . opcode = OPCODE_CONNECT_BSSID ;
// Set Default BSSID
bssid . mac = user - > resolver . mac ;
// No Group found
if ( g = = NULL )
{
// Allocate Group Memory
g = ( SceNetAdhocctlGroupNode * ) malloc ( sizeof ( SceNetAdhocctlGroupNode ) ) ;
// Allocated Group Memory
if ( g ! = NULL )
{
// Clear Memory
memset ( g , 0 , sizeof ( SceNetAdhocctlGroupNode ) ) ;
// Link Game Node
g - > game = user - > game ;
// Link Group Node
g - > next = g - > game - > group ;
if ( g - > game - > group ! = NULL ) g - > game - > group - > prev = g ;
g - > game - > group = g ;
// Copy Group Name
g - > group = * group ;
// Increase Group Counter for Game
g - > game - > groupcount + + ;
}
}
// Group now available
if ( g ! = NULL )
{
// Iterate remaining Group Players
SceNetAdhocctlUserNode * peer = g - > player ;
while ( peer ! = NULL )
{
// Connect Packet
SceNetAdhocctlConnectPacketS2C packet ;
// Clear Memory
// memset(&packet, 0, sizeof(packet));
// Set Connect Opcode
packet . base . opcode = OPCODE_CONNECT ;
// Set Player Name
packet . name = user - > resolver . name ;
// Set Player MAC
packet . mac = user - > resolver . mac ;
// Set Player IP
packet . ip = user - > resolver . ip ;
// Send Data
2014-08-11 16:06:09 +00:00
int iResult = send ( peer - > stream , ( const char * ) & packet , sizeof ( packet ) , 0 ) ;
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: connect_user[send peer] (Socket error %d) " , errno ) ;
2014-07-31 18:55:42 +00:00
// Set Player Name
packet . name = peer - > resolver . name ;
// Set Player MAC
packet . mac = peer - > resolver . mac ;
// Set Player IP
packet . ip = peer - > resolver . ip ;
// Send Data
2014-08-11 16:06:09 +00:00
iResult = send ( user - > stream , ( const char * ) & packet , sizeof ( packet ) , 0 ) ;
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: connect_user[send user] (Socket error %d) " , errno ) ;
2014-07-31 18:55:42 +00:00
// Set BSSID
if ( peer - > group_next = = NULL ) bssid . mac = peer - > resolver . mac ;
// Move Pointer
peer = peer - > group_next ;
}
// Link User to Group
user - > group_next = g - > player ;
if ( g - > player ! = NULL ) g - > player - > group_prev = user ;
g - > player = user ;
// Link Group to User
user - > group = g ;
// Increase Player Count
g - > playercount + + ;
// Send Network BSSID to User
2014-08-11 16:06:09 +00:00
int iResult = send ( user - > stream , ( const char * ) & bssid , sizeof ( bssid ) , 0 ) ;
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: connect_user[send user bssid] (Socket error %d) " , errno ) ;
2014-07-31 18:55:42 +00:00
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) joined %s group %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr , safegroupstr ) ;
// Update Status Log
update_status ( ) ;
// Exit Function
return ;
}
}
// Already connected to another group
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) group - > data , ADHOCCTL_GROUPNAME_LEN ) ;
char safegroupstr2 [ 9 ] ;
memset ( safegroupstr2 , 0 , sizeof ( safegroupstr2 ) ) ;
strncpy ( safegroupstr2 , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to join %s group %s without disconnecting from %s first " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr , safegroupstr , safegroupstr2 ) ;
}
}
// Invalid Group Name
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) group - > data , ADHOCCTL_GROUPNAME_LEN ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to join invalid %s group %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr , safegroupstr ) ;
}
// Invalid State, Out of Memory or Invalid Group Name
logout_user ( user ) ;
}
/**
* Disconnect User from Game Group
* @ param user User Node
*/
void disconnect_user ( SceNetAdhocctlUserNode * user )
{
// User is connected
if ( user - > group ! = NULL )
{
// Unlink Leftside (Beginning)
if ( user - > group_prev = = NULL ) user - > group - > player = user - > group_next ;
// Unlink Leftside (Other)
else user - > group_prev - > group_next = user - > group_next ;
// Unlink Rightside
if ( user - > group_next ! = NULL ) user - > group_next - > group_prev = user - > group_prev ;
// Fix Player Count
user - > group - > playercount - - ;
// Iterate remaining Group Players
SceNetAdhocctlUserNode * peer = user - > group - > player ;
while ( peer ! = NULL )
{
// Disconnect Packet
SceNetAdhocctlDisconnectPacketS2C packet ;
// Clear Memory
// memset(&packet, 0, sizeof(packet));
// Set Disconnect Opcode
packet . base . opcode = OPCODE_DISCONNECT ;
// Set User IP
packet . ip = user - > resolver . ip ;
// Send Data
2014-08-11 16:06:09 +00:00
int iResult = send ( peer - > stream , ( const char * ) & packet , sizeof ( packet ) , 0 ) ;
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: disconnect_user[send peer] (Socket error %d) " , errno ) ;
2014-07-31 18:55:42 +00:00
// Move Pointer
peer = peer - > group_next ;
}
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) left %s group %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr , safegroupstr ) ;
// Empty Group
if ( user - > group - > playercount = = 0 )
{
// Unlink Leftside (Beginning)
if ( user - > group - > prev = = NULL ) user - > group - > game - > group = user - > group - > next ;
// Unlink Leftside (Other)
else user - > group - > prev - > next = user - > group - > next ;
// Unlink Rightside
if ( user - > group - > next ! = NULL ) user - > group - > next - > prev = user - > group - > prev ;
// Free Group Memory
free ( user - > group ) ;
// Decrease Group Counter in Game Node
user - > game - > groupcount - - ;
}
// Unlink from Group
user - > group = NULL ;
user - > group_next = NULL ;
user - > group_prev = NULL ;
// Update Status Log
update_status ( ) ;
// Exit Function
return ;
}
// Not in a game group
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to leave %s group without joining one first " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr ) ;
}
// Delete User
logout_user ( user ) ;
}
/**
* Send Game Group List
* @ param user User Node
*/
void send_scan_results ( SceNetAdhocctlUserNode * user )
{
// User is disconnected
if ( user - > group = = NULL )
{
// Iterate Groups
SceNetAdhocctlGroupNode * group = user - > game - > group ;
for ( ; group ! = NULL ; group = group - > next )
{
// Scan Result Packet
SceNetAdhocctlScanPacketS2C packet ;
// Clear Memory
// memset(&packet, 0, sizeof(packet));
// Set Opcode
packet . base . opcode = OPCODE_SCAN ;
// Set Group Name
packet . group = group - > group ;
// Iterate Players in Network Group
SceNetAdhocctlUserNode * peer = group - > player ;
for ( ; peer ! = NULL ; peer = peer - > group_next )
{
// Found Network Founder
if ( peer - > group_next = = NULL )
{
// Set Group Host MAC
packet . mac = peer - > resolver . mac ;
}
}
// Send Group Packet
2014-08-11 16:06:09 +00:00
int iResult = send ( user - > stream , ( const char * ) & packet , sizeof ( packet ) , 0 ) ;
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: send_scan_result[send user] (Socket error %d) " , errno ) ;
2014-07-31 18:55:42 +00:00
}
// Notify Player of End of Scan
uint8_t opcode = OPCODE_SCAN_COMPLETE ;
2014-08-11 16:06:09 +00:00
int iResult = send ( user - > stream , ( const char * ) & opcode , 1 , 0 ) ;
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: send_scan_result[send peer complete] (Socket error %d) " , errno ) ;
2014-07-31 18:55:42 +00:00
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) requested information on %d %s groups " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , user - > game - > groupcount , safegamestr ) ;
// Exit Function
return ;
}
// User in a game group
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to scan for %s groups without disconnecting from %s first " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr , safegroupstr ) ;
}
// Delete User
logout_user ( user ) ;
}
/**
* Spread Chat Message in P2P Network
* @ param user Sender User Node
* @ param message Chat Message
*/
2015-01-11 22:23:03 +00:00
void spread_message ( SceNetAdhocctlUserNode * user , const char * message )
2014-07-31 18:55:42 +00:00
{
// Global Notice
if ( user = = NULL )
{
// Iterate Players
for ( user = _db_user ; user ! = NULL ; user = user - > next )
{
// Player has access to chat
if ( user - > group ! = NULL )
{
// Chat Packet
SceNetAdhocctlChatPacketS2C packet ;
// Clear Memory
memset ( & packet , 0 , sizeof ( packet ) ) ;
// Set Chat Opcode
packet . base . base . opcode = OPCODE_CHAT ;
// Set Chat Message
strcpy ( packet . base . message , message ) ;
// Send Data
2014-08-11 16:06:09 +00:00
int iResult = send ( user - > stream , ( const char * ) & packet , sizeof ( packet ) , 0 ) ;
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: spread_message[send user chat] (Socket error %d) " , errno ) ;
2014-07-31 18:55:42 +00:00
}
}
// Prevent NULL Error
return ;
}
// User is connected
else if ( user - > group ! = NULL )
{
// Broadcast Range Counter
uint32_t counter = 0 ;
// Iterate Group Players
SceNetAdhocctlUserNode * peer = user - > group - > player ;
while ( peer ! = NULL )
{
// Skip Self
if ( peer = = user )
{
// Move Pointer
peer = peer - > group_next ;
// Continue Loop
continue ;
}
// Chat Packet
SceNetAdhocctlChatPacketS2C packet ;
// Set Chat Opcode
packet . base . base . opcode = OPCODE_CHAT ;
// Set Chat Message
strcpy ( packet . base . message , message ) ;
// Set Sender Nickname
packet . name = user - > resolver . name ;
// Send Data
2014-08-11 16:06:09 +00:00
int iResult = send ( peer - > stream , ( const char * ) & packet , sizeof ( packet ) , 0 ) ;
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: spread_message[send peer chat] (Socket error %d) " , errno ) ;
2014-07-31 18:55:42 +00:00
// Move Pointer
peer = peer - > group_next ;
// Increase Broadcast Range Counter
counter + + ;
}
// Message Sent
if ( counter > 0 )
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) sent \" %s \" to %d players in %s group %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , message , counter , safegamestr , safegroupstr ) ;
}
// Exit Function
return ;
}
// User not in a game group
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) attempted to send a text message without joining a %s group first " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] , safegamestr ) ;
}
// Delete User
logout_user ( user ) ;
}
/**
* Get User State
* @ param user User Node
*/
int get_user_state ( SceNetAdhocctlUserNode * user )
{
// Timeout Status
if ( ( time ( NULL ) - user - > last_recv ) > = SERVER_USER_TIMEOUT ) return USER_STATE_TIMED_OUT ;
// Waiting Status
if ( user - > game = = NULL ) return USER_STATE_WAITING ;
// Logged-In Status
return USER_STATE_LOGGED_IN ;
}
/**
* Clear RX Buffer
* @ param user User Node
* @ param clear Number of Bytes to clear ( - 1 for all )
*/
void clear_user_rxbuf ( SceNetAdhocctlUserNode * user , int clear )
{
// Fix Clear Length
if ( clear = = - 1 | | clear > ( int ) user - > rxpos ) clear = user - > rxpos ;
// Move Buffer
memmove ( user - > rx , user - > rx + clear , sizeof ( user - > rx ) - clear ) ;
// Fix RX Buffer Pointer
user - > rxpos - = clear ;
}
/**
* Patch Game Product Code
* @ param product To - be - patched Product Code
* @ param from If the Product Code matches this . . .
* @ param to . . . then change it to this one .
*/
void game_product_relink ( SceNetAdhocctlProductCode * product , char * from , char * to )
{
// Relink Region Code
if ( strncmp ( product - > data , from , PRODUCT_CODE_LENGTH ) = = 0 ) strncpy ( product - > data , to , PRODUCT_CODE_LENGTH ) ;
}
/**
* Game Product Override ( used for mixing multi - region games )
* @ param product IN : Source Product OUT : Override Product
*/
void game_product_override ( SceNetAdhocctlProductCode * product )
{
// Safe Product Code
char productid [ PRODUCT_CODE_LENGTH + 1 ] ;
// Prepare Safe Product Code
strncpy ( productid , product - > data , PRODUCT_CODE_LENGTH ) ;
productid [ PRODUCT_CODE_LENGTH ] = 0 ;
// Database Handle
//sqlite3 * db = NULL;
// Open Database
//if(sqlite3_open(SERVER_DATABASE, &db) == SQLITE_OK)
{
// Crosslinked Flag
int crosslinked = 0 ;
// Exists Flag
int exists = 0 ;
// SQL Statements
/*const char * sql = "SELECT id_to FROM crosslinks WHERE id_from=?;";
const char * sql2 = " SELECT * FROM productids WHERE id=?; " ;
const char * sql3 = " INSERT INTO productids(id, name) VALUES(?, ?); " ;
// Prepared SQL Statement
sqlite3_stmt * statement = NULL ;
// Prepare SQL Statement
if ( sqlite3_prepare_v2 ( db , sql , strlen ( sql ) + 1 , & statement , NULL ) = = SQLITE_OK )
{
// Bind SQL Statement Data
if ( sqlite3_bind_text ( statement , 1 , productid , strlen ( productid ) , SQLITE_STATIC ) = = SQLITE_OK )
{
// Found Matching Row
if ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
// Grab Crosslink ID
const char * crosslink = ( const char * ) sqlite3_column_text ( statement , 0 ) ;
// Crosslink Product Code
strncpy ( product - > data , crosslink , PRODUCT_CODE_LENGTH ) ;
// Log Crosslink
INFO_LOG ( SCENET , " Crosslinked %s to %s " , productid , crosslink ) ;
// Set Crosslinked Flag
crosslinked = 1 ;
}
}
// Destroy Prepared SQL Statement
sqlite3_finalize ( statement ) ;
} */
for ( std : : vector < db_crosslink > : : iterator it = crosslinks . begin ( ) ; it ! = crosslinks . end ( ) ; it + + ) {
if ( IsMatch ( it - > id_from , productid ) ) {
// Grab Crosslink ID
char crosslink [ PRODUCT_CODE_LENGTH + 1 ] ;
strncpy ( crosslink , it - > id_to , PRODUCT_CODE_LENGTH ) ;
crosslink [ PRODUCT_CODE_LENGTH ] = 0 ; // null terminated
// Crosslink Product Code
strncpy ( product - > data , it - > id_to , PRODUCT_CODE_LENGTH ) ;
// Log Crosslink
INFO_LOG ( SCENET , " AdhocServer: Crosslinked %s to %s " , productid , crosslink ) ;
// Set Crosslinked Flag
crosslinked = 1 ;
break ;
}
}
// Not Crosslinked
if ( ! crosslinked )
{
// Prepare SQL Statement
/*if(sqlite3_prepare_v2(db, sql2, strlen(sql2) + 1, &statement, NULL) == SQLITE_OK)
{
// Bind SQL Statement Data
if ( sqlite3_bind_text ( statement , 1 , productid , strlen ( productid ) , SQLITE_STATIC ) = = SQLITE_OK )
{
// Found Matching Row
if ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
// Set Exists Flag
exists = 1 ;
}
}
// Destroy Prepare SQL Statement
sqlite3_finalize ( statement ) ;
} */
for ( std : : vector < db_productid > : : iterator it = productids . begin ( ) ; it ! = productids . end ( ) ; it + + ) {
if ( IsMatch ( it - > id , productid ) ) {
// Set Exists Flag
exists = 1 ;
break ;
}
}
// Game doesn't exist in Database
if ( ! exists )
{
// Prepare SQL Statement
/*if(sqlite3_prepare_v2(db, sql3, strlen(sql3) + 1, &statement, NULL) == SQLITE_OK)
{
// Bind SQL Statement Data
if ( sqlite3_bind_text ( statement , 1 , productid , strlen ( productid ) , SQLITE_STATIC ) = = SQLITE_OK & & sqlite3_bind_text ( statement , 2 , productid , strlen ( productid ) , SQLITE_STATIC ) = = SQLITE_OK )
{
// Save Product ID to Database
if ( sqlite3_step ( statement ) = = SQLITE_DONE )
{
// Log Addition
INFO_LOG ( SCENET , " Added Unknown Product ID %s to Database " , productid ) ;
}
}
// Destroy Prepare SQL Statement
sqlite3_finalize ( statement ) ;
} */
db_productid unkproduct ;
strncpy ( unkproduct . id , productid , sizeof ( unkproduct . id ) ) ;
strncpy ( unkproduct . name , productid , sizeof ( productid ) ) ;
productids . push_back ( unkproduct ) ; //productids[productids.size()] = unkproduct;
// Log Addition
INFO_LOG ( SCENET , " AdhocServer: Added Unknown Product ID %s to Database " , productid ) ;
}
}
// Close Database
//sqlite3_close(db);
}
}
/**
* Update Status Logfile
*/
void update_status ( void )
{
// Open Logfile
FILE * log = fopen ( SERVER_STATUS_XMLOUT , " w " ) ;
// Opened Logfile
if ( log ! = NULL )
{
// Write XML Header
fprintf ( log , " <?xml version= \" 1.0 \" encoding= \" UTF-8 \" ?> \n " ) ;
// Write XSL Processor Information
fprintf ( log , " <?xml-stylesheet type= \" text/xsl \" href= \" status.xsl \" ?> \n " ) ;
// Output Root Tag + User Count
fprintf ( log , " <prometheus usercount= \" %u \" > \n " , _db_user_count ) ;
// Database Handle
//sqlite3 * db = NULL;
// Open Database
//if(sqlite3_open(SERVER_DATABASE, &db) == SQLITE_OK)
{
// Iterate Games
SceNetAdhocctlGameNode * game = _db_game ; for ( ; game ! = NULL ; game = game - > next )
{
// Safe Product ID
char productid [ PRODUCT_CODE_LENGTH + 1 ] ;
strncpy ( productid , game - > game . data , PRODUCT_CODE_LENGTH ) ;
productid [ PRODUCT_CODE_LENGTH ] = 0 ;
// Display Name
char displayname [ 128 ] ;
memset ( displayname , 0 , sizeof ( displayname ) ) ;
// SQL Statement
//const char * sql = "SELECT name FROM productids WHERE id=?;";
// Prepared SQL Statement
//sqlite3_stmt * statement = NULL;
// Prepare SQL Statement
/*if(sqlite3_prepare_v2(db, sql, strlen(sql) + 1, &statement, NULL) == SQLITE_OK)
{
// Bind SQL Statement Data
if ( sqlite3_bind_text ( statement , 1 , productid , strlen ( productid ) , SQLITE_STATIC ) = = SQLITE_OK )
{
// Found Matching Row
if ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
// Fetch Game Name from Database
const char * gamename = ( const char * ) sqlite3_column_text ( statement , 0 ) ;
// Copy Game Name
strcpyxml ( displayname , gamename , sizeof ( displayname ) ) ;
}
// Game not in Database
else
{
// Use Product Code as Name
strcpyxml ( displayname , productid , sizeof ( displayname ) ) ;
}
}
// Destroy Prepared SQL Statement
sqlite3_finalize ( statement ) ;
} */
//db_productid *foundid = NULL;
bool found = false ;
for ( std : : vector < db_productid > : : iterator it = productids . begin ( ) ; it ! = productids . end ( ) ; it + + ) {
if ( IsMatch ( it - > id , productid ) ) {
// Copy Game Name
strcpyxml ( displayname , it - > name , sizeof ( displayname ) ) ;
found = true ;
break ;
}
}
if ( ! found ) {
// Use Product Code as Name
strcpyxml ( displayname , productid , sizeof ( displayname ) ) ;
}
// Output Game Tag + Game Name
fprintf ( log , " \t <game name= \" %s \" usercount= \" %u \" > \n " , displayname , game - > playercount ) ;
// Activate User Count
uint32_t activecount = 0 ;
// Iterate Game Groups
SceNetAdhocctlGroupNode * group = game - > group ; for ( ; group ! = NULL ; group = group - > next )
{
// Safe Group Name
char groupname [ ADHOCCTL_GROUPNAME_LEN + 1 ] ;
strncpy ( groupname , ( const char * ) group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
groupname [ ADHOCCTL_GROUPNAME_LEN ] = 0 ;
// Output Group Tag + Group Name + User Count
fprintf ( log , " \t \t <group name= \" %s \" usercount= \" %u \" > \n " , strcpyxml ( displayname , groupname , sizeof ( displayname ) ) , group - > playercount ) ;
// Iterate Users
SceNetAdhocctlUserNode * user = group - > player ; for ( ; user ! = NULL ; user = user - > group_next )
{
// Output User Tag + Username
fprintf ( log , " \t \t \t <user>%s</user> \n " , strcpyxml ( displayname , ( const char * ) user - > resolver . name . data , sizeof ( displayname ) ) ) ;
}
// Output Closing Group Tag
fprintf ( log , " \t \t </group> \n " ) ;
// Increase Active Game User Count
activecount + = group - > playercount ;
}
// Output Idle Game Group
if ( game - > playercount > activecount )
{
// Output Group Tag + Group Name + Idle User Count
fprintf ( log , " \t \t <group name= \" Groupless \" usercount= \" %u \" /> \n " , game - > playercount - activecount ) ;
}
// Output Closing Game Tag
fprintf ( log , " \t </game> \n " ) ;
}
// Close Database
//sqlite3_close(db);
}
// Output Closing Root Tag
fprintf ( log , " </prometheus> " ) ;
// Close Logfile
fclose ( log ) ;
}
}
/**
* Escape XML Sequences to avoid malformed XML files .
* @ param out Out Buffer
* @ param in In Buffer
* @ param size Size of Out Buffer
* @ return Reference to Out Buffer
*/
const char * strcpyxml ( char * out , const char * in , uint32_t size )
{
// Valid Arguments
if ( out ! = NULL & & in ! = NULL & & size > 0 )
{
// Clear Memory
memset ( out , 0 , size ) ;
// Written Size Pointer
uint32_t written = 0 ;
// Iterate In-Buffer Symbols
uint32_t i = 0 ; for ( ; i < strlen ( in ) ; i + + )
{
// " Symbol
if ( in [ i ] = = ' " ' )
{
// Enough Space in Out-Buffer (6B for ")
if ( ( size - written ) > 6 )
{
// Write Escaped Sequence
strcpy ( out + written , " " " ) ;
// Move Pointer
written + = 6 ;
}
// Truncate required
else break ;
}
// < Symbol
else if ( in [ i ] = = ' < ' )
{
// Enough Space in Out-Buffer (4B for <)
if ( ( size - written ) > 4 )
{
// Write Escaped Sequence
strcpy ( out + written , " < " ) ;
// Move Pointer
written + = 4 ;
}
// Truncate required
else break ;
}
// > Symbol
else if ( in [ i ] = = ' > ' )
{
// Enough Space in Out-Buffer (4B for >)
if ( ( size - written ) > 4 )
{
// Write Escaped Sequence
strcpy ( out + written , " > " ) ;
// Move Pointer
written + = 4 ;
}
// Truncate required
else break ;
}
// & Symbol
else if ( in [ i ] = = ' & ' )
{
// Enough Space in Out-Buffer (5B for &)
if ( ( size - written ) > 5 )
{
// Write Escaped Sequence
strcpy ( out + written , " & " ) ;
// Move Pointer
written + = 5 ;
}
// Truncate required
else break ;
}
// Normal Character
else
{
// Enough Space in Out-Buffer (1B)
if ( ( size - written ) > 1 )
{
// Write Character
out [ written + + ] = in [ i ] ;
}
}
}
// Return Reference
return out ;
}
// Invalid Arguments
return NULL ;
}
/**
* Server Entry Point
* @ param argc Number of Arguments
* @ param argv Arguments
* @ return OS Error Code
*/
int proAdhocServerThread ( int port ) // (int argc, char * argv[])
{
// Result
int result = 0 ;
INFO_LOG ( SCENET , " AdhocServer: Begin of AdhocServer Thread " ) ;
// Create Signal Receiver for CTRL + C
//signal(SIGINT, interrupt);
// Create Signal Receiver for kill / killall
//signal(SIGTERM, interrupt);
// Create Listening Socket
int server = create_listen_socket ( port ) ; //SERVER_PORT
// Created Listening Socket
if ( server ! = - 1 )
{
// Notify User
INFO_LOG ( SCENET , " AdhocServer: Listening for Connections on TCP Port %u " , port ) ; //SERVER_PORT
// Enter Server Loop
result = server_loop ( server ) ;
// Notify User
INFO_LOG ( SCENET , " AdhocServer: Shutdown complete " ) ;
}
//_status = 0;
adhocServerRunning = false ;
INFO_LOG ( SCENET , " AdhocServer: End of AdhocServer Thread " ) ;
// Return Result
return result ;
}
/**
* Server Shutdown Request Handler
* @ param sig Captured Signal
*/
void interrupt ( int sig )
{
// Notify User
INFO_LOG ( SCENET , " AdhocServer: Shutting down... please wait " ) ;
// Trigger Shutdown
//_status = 0;
adhocServerRunning = false ;
}
/**
* Enable Address Reuse on Socket
* @ param fd Socket
*/
void enable_address_reuse ( int fd )
{
// Enable Value
int on = 1 ;
// Enable Port Reuse
setsockopt ( fd , SOL_SOCKET , SO_REUSEADDR , ( const char * ) & on , sizeof ( on ) ) ;
}
/**
* Change Socket Blocking Mode
* @ param fd Socket
* @ param nonblocking 1 for Nonblocking , 0 for Blocking
*/
void change_blocking_mode ( int fd , int nonblocking )
{
unsigned long on = 1 ;
unsigned long off = 0 ;
# ifdef _MSC_VER
if ( nonblocking ) {
// Change to Non-Blocking Mode
ioctlsocket ( fd , FIONBIO , & on ) ;
}
else {
// Change to Blocking Mode
ioctlsocket ( fd , FIONBIO , & off ) ;
}
# else
// Change to Non-Blocking Mode
if ( nonblocking ) fcntl ( fd , F_SETFL , O_NONBLOCK ) ;
// Change to Blocking Mode
else
{
// Get Flags
int flags = fcntl ( fd , F_GETFL ) ;
// Remove Non-Blocking Flag
fcntl ( fd , F_SETFL , flags & ~ O_NONBLOCK ) ;
}
# endif
}
/**
* Create Port - Bound Listening Socket
* @ param port TCP Port
* @ return Socket Descriptor
*/
int create_listen_socket ( uint16_t port )
{
// Create Socket
int fd = ( int ) socket ( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
// Created Socket
if ( fd ! = - 1 )
{
// Enable Address Reuse
enable_address_reuse ( fd ) ; // Shouldn't Reuse the port for built-in AdhocServer to prevent conflict with Dedicated AdhocServer
// Make Socket Nonblocking
change_blocking_mode ( fd , 1 ) ;
// Prepare Local Address Information
struct sockaddr_in local ;
memset ( & local , 0 , sizeof ( local ) ) ;
local . sin_family = AF_INET ;
local . sin_addr . s_addr = INADDR_ANY ;
local . sin_port = htons ( port ) ;
// Bind Local Address to Socket
int bindresult = bind ( fd , ( struct sockaddr * ) & local , sizeof ( local ) ) ;
// Bound Local Address to Socket
if ( bindresult ! = - 1 )
{
// Switch Socket into Listening Mode
listen ( fd , SERVER_LISTEN_BACKLOG ) ;
// Return Socket
return fd ;
}
// Notify User
2014-08-11 16:06:09 +00:00
else ERROR_LOG ( SCENET , " AdhocServer: Bind returned %i (Socket error %d) " , bindresult, errno) ;
2014-07-31 18:55:42 +00:00
// Close Socket
closesocket ( fd ) ;
}
// Notify User
2014-08-11 16:06:09 +00:00
else ERROR_LOG ( SCENET , " AdhocServer: Socket returned %i (Socket error %d) " , fd, errno) ;
2014-07-31 18:55:42 +00:00
// Return Error
return - 1 ;
}
/**
* Server Main Loop
* @ param server Server Listening Socket
* @ return OS Error Code
*/
int server_loop ( int server )
{
// Set Running Status
//_status = 1;
adhocServerRunning = true ;
// Create Empty Status Logfile
update_status ( ) ;
// Handling Loop
while ( adhocServerRunning ) //(_status == 1)
{
// Login Block
{
// Login Result
int loginresult = 0 ;
// Login Processing Loop
do
{
// Prepare Address Structure
struct sockaddr_in addr ;
socklen_t addrlen = sizeof ( addr ) ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
// Accept Login Requests
// loginresult = accept4(server, (struct sockaddr *)&addr, &addrlen, SOCK_NONBLOCK);
// Alternative Accept Approach (some Linux Kernel don't support the accept4 Syscall... wtf?)
loginresult = accept ( server , ( struct sockaddr * ) & addr , & addrlen ) ;
if ( loginresult ! = - 1 )
{
// Switch Socket into Non-Blocking Mode
change_blocking_mode ( loginresult , 1 ) ;
}
// Login User (Stream)
if ( loginresult ! = - 1 ) {
u32_le sip = addr . sin_addr . s_addr ;
if ( sip = = 0x0100007f ) { //127.0.0.1 should be replaced with LAN/WAN IP whenever available
char str [ 100 ] ;
gethostname ( str , 100 ) ;
u8 * pip = ( u8 * ) & sip ;
if ( gethostbyname ( str ) - > h_addrtype = = AF_INET & & gethostbyname ( str ) - > h_addr_list [ 0 ] ! = NULL ) pip = ( u8 * ) gethostbyname ( str ) - > h_addr_list [ 0 ] ;
sip = * ( u32_le * ) pip ;
WARN_LOG ( SCENET , " AdhocServer: Replacing IP %s with %u.%u.%u.%u " , inet_ntoa ( addr . sin_addr ) , pip [ 0 ] , pip [ 1 ] , pip [ 2 ] , pip [ 3 ] ) ;
}
login_user_stream ( loginresult , sip ) ;
}
} while ( loginresult ! = - 1 ) ;
}
// Receive Data from Users
SceNetAdhocctlUserNode * user = _db_user ;
while ( user ! = NULL )
{
// Next User (for safe delete)
SceNetAdhocctlUserNode * next = user - > next ;
// Receive Data from User
int recvresult = recv ( user - > stream , ( char * ) user - > rx + user - > rxpos , sizeof ( user - > rx ) - user - > rxpos , 0 ) ;
// Connection Closed or Timed Out
if ( recvresult = = 0 | | ( recvresult = = - 1 & & errno ! = EAGAIN & & errno ! = EWOULDBLOCK ) | | get_user_state ( user ) = = USER_STATE_TIMED_OUT )
{
// Logout User
logout_user ( user ) ;
}
// Received Data (or leftovers in RX-Buffer)
else if ( recvresult > 0 | | user - > rxpos > 0 )
{
// New Incoming Data
if ( recvresult > 0 )
{
// Move RX Pointer
user - > rxpos + = recvresult ;
// Update Death Clock
user - > last_recv = time ( NULL ) ;
}
// Waiting for Login Packet
if ( get_user_state ( user ) = = USER_STATE_WAITING )
{
// Valid Opcode
if ( user - > rx [ 0 ] = = OPCODE_LOGIN )
{
// Enough Data available
if ( user - > rxpos > = sizeof ( SceNetAdhocctlLoginPacketC2S ) )
{
// Clone Packet
SceNetAdhocctlLoginPacketC2S packet = * ( SceNetAdhocctlLoginPacketC2S * ) user - > rx ;
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , sizeof ( SceNetAdhocctlLoginPacketC2S ) ) ;
// Login User (Data)
login_user_data ( user , & packet ) ;
}
}
// Invalid Opcode
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
INFO_LOG ( SCENET , " AdhocServer: Invalid Opcode 0x%02X in Waiting State from %u.%u.%u.%u " , user - > rx [ 0 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] ) ;
// Logout User
logout_user ( user ) ;
}
}
// Logged-In User
else if ( get_user_state ( user ) = = USER_STATE_LOGGED_IN )
{
// Ping Packet
if ( user - > rx [ 0 ] = = OPCODE_PING )
{
// Delete Packet from RX Buffer
clear_user_rxbuf ( user , 1 ) ;
}
// Group Connect Packet
else if ( user - > rx [ 0 ] = = OPCODE_CONNECT )
{
// Enough Data available
if ( user - > rxpos > = sizeof ( SceNetAdhocctlConnectPacketC2S ) )
{
// Cast Packet
SceNetAdhocctlConnectPacketC2S * packet = ( SceNetAdhocctlConnectPacketC2S * ) user - > rx ;
// Clone Group Name
SceNetAdhocctlGroupName group = packet - > group ;
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , sizeof ( SceNetAdhocctlConnectPacketC2S ) ) ;
// Change Game Group
connect_user ( user , & group ) ;
}
}
// Group Disconnect Packet
else if ( user - > rx [ 0 ] = = OPCODE_DISCONNECT )
{
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , 1 ) ;
// Leave Game Group
disconnect_user ( user ) ;
}
// Network Scan Packet
else if ( user - > rx [ 0 ] = = OPCODE_SCAN )
{
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , 1 ) ;
// Send Network List
send_scan_results ( user ) ;
}
// Chat Text Packet
else if ( user - > rx [ 0 ] = = OPCODE_CHAT )
{
// Enough Data available
if ( user - > rxpos > = sizeof ( SceNetAdhocctlChatPacketC2S ) )
{
// Cast Packet
SceNetAdhocctlChatPacketC2S * packet = ( SceNetAdhocctlChatPacketC2S * ) user - > rx ;
// Clone Buffer for Message
char message [ 64 ] ;
memset ( message , 0 , sizeof ( message ) ) ;
strncpy ( message , packet - > message , sizeof ( message ) - 1 ) ;
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , sizeof ( SceNetAdhocctlChatPacketC2S ) ) ;
// Spread Chat Message
spread_message ( user , message ) ;
}
}
// Invalid Opcode
else
{
// Notify User
uint8_t * ip = ( uint8_t * ) & user - > resolver . ip ;
INFO_LOG ( SCENET , " AdhocServer: Invalid Opcode 0x%02X in Logged-In State from %s (MAC: %02X:%02X:%02X:%02X:%02X:%02X - IP: %u.%u.%u.%u) " , user - > rx [ 0 ] , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] ) ;
// Logout User
logout_user ( user ) ;
}
}
}
// Move Pointer
user = next ;
}
// Prevent needless CPU Overload (1ms Sleep)
sleep_ms ( 1 ) ;
// Don't do anything if it's paused, otherwise the log will be flooded
while ( adhocServerRunning & & Core_IsStepping ( ) ) sleep_ms ( 1 ) ;
}
// Free User Database Memory
free_database ( ) ;
// Close Server Socket
closesocket ( server ) ;
// Return Success
return 0 ;
}