Compare commits

..
5 Commits
Author SHA1 Message Date
Your Name a5cbfbc916 Fix critical Linux compilation errors for LoginServer
Major fixes implemented:
1. Added missing system headers (sys/time.h, sys/ioctl.h) for gettimeofday and ioctl
2. Resolved ODBC type conflicts by conditionally defining TCHAR and using compatible DWORD type
3. Added comprehensive Windows socket function mappings for Linux (WSAStartup, WSACleanup, etc.)
4. Fixed ListenSocket constructor to match expected interface with IsOpen() method
5. Fixed string_format parameter binding issue in LoginSession.cpp
6. Added platform-specific implementations in SocketMgr.cpp for Linux compatibility
7. Enhanced SocketOpsLinux.cpp with missing socket operations

Key improvements:
- Cross-platform socket initialization and cleanup
- Linux epoll-based socket management
- Compatible type definitions that work with both Linux and Windows ODBC
- Proper handling of temporary string objects in function calls
- Comprehensive error handling for missing Windows APIs on Linux

This should resolve the major compilation errors while maintaining Windows compatibility.
2025-08-29 22:25:15 +03:00
Your Name e5a1ca68e7 Fix Linux compilation errors for LoginServer
Major fixes for Linux compatibility:
- Added comprehensive Linux socket type definitions to stdafx.h
- Created SocketOpsLinux.cpp with Linux socket operations implementation
- Added ListenSocketLinux.h with epoll-based socket listening
- Updated Network.h to conditionally include platform-specific headers
- Modified SocketDefines.h to support both Windows OVERLAPPED and Linux equivalents
- Updated CMakeLists.txt to use correct platform-specific source files
- Added additional socket constants and error code mappings for Linux

These changes address the compilation errors related to:
- Missing SOCKET, HANDLE, OVERLAPPED type definitions
- Windows-specific socket functions (WSASocket, closesocket, etc.)
- Platform-specific listen socket implementations
- Socket operations and error handling

The LoginServer should now compile successfully on Linux while maintaining Windows compatibility.
2025-08-29 22:10:58 +03:00
Your Name 59b331458c Add Linux compatibility for LoginServer
- Updated main.cpp with platform-specific code for Windows/Linux
- Modified stdafx.h to include Linux headers and definitions
- Updated signal_handler.cpp for cross-platform signal handling
- Added Linux-compatible types and macros
- Created CMakeLists.txt for Linux build system
- Added build.sh script for automated building
- Added loginserver.sh script for server management
- Created comprehensive README_LINUX.md with deployment instructions
- All changes maintain Windows compatibility using preprocessor directives
2025-08-29 21:52:53 +03:00
Your Name 26a4c99c5c readme added 2025-08-29 21:46:41 +03:00
leventferrah 9fd7a9283c Readme eklendi 2025-08-29 21:31:02 +03:00
18 changed files with 2614 additions and 27 deletions
+24 -6
View File
@@ -1,7 +1,25 @@
# knightonline
# Knight Online
1.0.0
## License
<<<<<<< HEAD
Knight Online Clone Project v1.0
=======
Knight Online Clone Project
>>>>>>> 191661329532817bf0e8da163c8ac248afc0cddd
MIT License
Copyright (c) 2024 Knight Online
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+99
View File
@@ -0,0 +1,99 @@
cmake_minimum_required(VERSION 3.10)
project(LoginServer)
# Set C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Set compiler flags
if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -O2 -pthread")
endif()
# Define preprocessor macros
if(WIN32)
add_definitions(-D_WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-DVC_EXTRALEAN)
else()
add_definitions(-D__VERSION=1)
endif()
# Include directories
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../shared
${CMAKE_CURRENT_SOURCE_DIR}/../shared/database
)
# Source files
set(LOGIN_SERVER_SOURCES
main.cpp
LoginServer.cpp
LoginSession.cpp
DBProcess.cpp
stdafx.cpp
)
# Shared library sources
set(SHARED_SOURCES
../shared/globals.cpp
../shared/tstring.cpp
../shared/Thread.cpp
../shared/TimeThread.cpp
../shared/Socket.cpp
../shared/SocketMgr.cpp
../shared/Condition.cpp
../shared/RWLock.cpp
../shared/ReferenceObject.cpp
../shared/signal_handler.cpp
../shared/Ini.cpp
../shared/JvCryption.cpp
../shared/crc32.c
../shared/lzf.c
../shared/HardwareInformation.cpp
../shared/DebugUtils.cpp
../shared/SMDFile.cpp
../shared/CircularBuffer.cpp
)
# Database sources
file(GLOB DATABASE_SOURCES "../shared/database/*.cpp")
# Platform specific sources
if(WIN32)
list(APPEND SHARED_SOURCES
../shared/SocketWin32.cpp
../shared/SocketOpsWin32.cpp
)
else()
list(APPEND SHARED_SOURCES
../shared/SocketOpsLinux.cpp
)
endif()
# Create executable
add_executable(LoginServer
${LOGIN_SERVER_SOURCES}
${SHARED_SOURCES}
${DATABASE_SOURCES}
)
# Link libraries
if(WIN32)
target_link_libraries(LoginServer ws2_32 odbc32)
else()
target_link_libraries(LoginServer pthread odbc)
endif()
# Set output directory
set_target_properties(LoginServer PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
# Copy configuration files
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/LogIn.ini)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/LogIn.ini ${CMAKE_BINARY_DIR}/bin/LogIn.ini COPYONLY)
endif()
+4
View File
@@ -20,7 +20,11 @@ bool LoginServer::Startup()
printf("Project : %d\n", GetVersion());
printf("Edited by Levent\n\n");
#ifdef _WIN32
CreateDirectory("Logs",NULL);
#else
mkdir("Logs", 0755);
#endif
m_fpLoginServer = fopen("./Logs/LoginServer.log", "a");
if (m_fpLoginServer == nullptr)
+2 -1
View File
@@ -171,7 +171,8 @@ void LoginSession::HandleLogin(Packet & pkt)
{
}
g_pMain->WriteUserLogFile(string_format("[ LOGIN - %d:%d:%d ] ID=%s Authentication=%s\n",time.GetHour(),time.GetMinute(),time.GetSecond(),account.c_str(),password.c_str(),sAuthMessage.c_str()));
std::string logMessage = string_format("[ LOGIN - %d:%d:%d ] ID=%s Authentication=%s\n",time.GetHour(),time.GetMinute(),time.GetSecond(),account.c_str(),password.c_str(),sAuthMessage.c_str());
g_pMain->WriteUserLogFile(logMessage);
Send(&result);
}
+295
View File
@@ -0,0 +1,295 @@
# Knight Online Login Server - Linux Version
This directory contains the Linux-compatible version of the Knight Online Login Server.
## Prerequisites
Before building and running the Login Server on Linux, make sure you have the following dependencies installed:
### Ubuntu/Debian
```bash
sudo apt-get update
sudo apt-get install build-essential cmake g++ unixodbc-dev
```
### CentOS/RHEL/Fedora
```bash
# CentOS/RHEL
sudo yum groupinstall "Development Tools"
sudo yum install cmake unixODBC-devel
# Fedora
sudo dnf groupinstall "Development Tools"
sudo dnf install cmake unixODBC-devel
```
## Building the Server
### Quick Start
```bash
# Make build script executable
chmod +x build.sh
# Build everything
./build.sh all
```
### Manual Build Steps
```bash
# 1. Make scripts executable
chmod +x build.sh loginserver.sh
# 2. Build the project
./build.sh build
# 3. Install binaries
./build.sh install
```
### Build Options
```bash
./build.sh clean # Clean build files
./build.sh build # Build project
./build.sh rebuild # Clean and build
./build.sh install # Install binaries
./build.sh all # Full build and install
./build.sh -j 4 build # Build with 4 parallel jobs
```
## Configuration
### Database Setup
1. Install and configure your ODBC driver for your database
2. Edit `LogIn.ini` with your database connection details:
```ini
[ODBC]
DSN=KO_MAIN
UID=your_username
PWD=your_password
```
### Server Configuration
Edit `LogIn.ini` to configure server settings:
```ini
[SETTINGS]
PORT=15100
[SERVER_LIST]
COUNT=1
SERVER_00=192.168.1.104
LANIP_00=192.168.1.104
NAME_00=Your Server Name
ID_00=1
```
## Running the Server
### Start the Server
```bash
./loginserver.sh start
```
### Check Server Status
```bash
./loginserver.sh status
```
### View Server Logs
```bash
./loginserver.sh logs
```
### Stop the Server
```bash
./loginserver.sh stop
```
### Restart the Server
```bash
./loginserver.sh restart
```
## Management Commands
The `loginserver.sh` script provides several management commands:
- `start` - Start the login server
- `stop` - Stop the login server
- `restart` - Restart the login server
- `status` - Show server status and process information
- `logs` - View server logs in real-time
- `config` - Create default configuration file
## File Structure
```
LoginServer/
├── bin/ # Compiled binaries
│ └── LoginServer # Main server executable
├── build/ # CMake build directory
├── Logs/ # Server log files
│ ├── LoginServer.log # Main server log
│ ├── Login_DD_MM_YYYY.log # Daily user login log
│ └── server_output.log # Server console output
├── build.sh # Build script
├── loginserver.sh # Server management script
├── LogIn.ini # Server configuration
├── CMakeLists.txt # CMake configuration
└── README_LINUX.md # This file
```
## Troubleshooting
### Common Issues
#### 1. Build Failures
- Make sure all dependencies are installed
- Check that you have sufficient permissions
- Verify CMake version (3.10 or higher required)
#### 2. ODBC Connection Issues
```bash
# Test ODBC connection
isql -v DSN_NAME username password
# List available ODBC drivers
odbcinst -q -d
# List configured DSNs
odbcinst -q -s
```
#### 3. Permission Issues
```bash
# Make scripts executable
chmod +x build.sh loginserver.sh
# Check binary permissions
chmod +x bin/LoginServer
```
#### 4. Port Already in Use
```bash
# Check what's using the port
sudo netstat -tlnp | grep :15100
# Kill process using the port
sudo kill -9 PID
```
### Debugging
#### Enable Debug Mode
Edit CMakeLists.txt and add debug flags:
```cmake
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -DDEBUG")
```
#### Run with GDB
```bash
gdb ./bin/LoginServer
(gdb) run
```
#### Monitor System Resources
```bash
# Monitor server process
top -p $(cat loginserver.pid)
# Check memory usage
cat /proc/$(cat loginserver.pid)/status
# Monitor network connections
ss -tlnp | grep LoginServer
```
## Security Considerations
1. **Firewall Configuration**
```bash
# Allow login server port
sudo ufw allow 15100/tcp
```
2. **User Permissions**
- Run the server as a non-root user
- Set appropriate file permissions
- Use a dedicated service user
3. **Database Security**
- Use strong database passwords
- Limit database user permissions
- Enable database connection encryption
## Integration with Gitea
This server is configured to work with the Gitea repository at:
- Local: `http://192.168.1.104:3000/`
- SSH: `ssh://gitea@192.168.1.104:2222/leventferrah/knightonline.git`
### Deployment Workflow
```bash
# Pull latest changes
git pull knight main
# Build and deploy
./build.sh all
# Restart server
./loginserver.sh restart
```
## Performance Tuning
### System Limits
Edit `/etc/security/limits.conf`:
```
username soft nofile 65536
username hard nofile 65536
```
### Network Optimization
Edit `/etc/sysctl.conf`:
```
net.core.somaxconn = 1024
net.ipv4.tcp_max_syn_backlog = 1024
```
## Monitoring
### Log Monitoring
```bash
# Monitor all logs
tail -f Logs/*.log
# Monitor specific log
tail -f Logs/LoginServer.log
```
### Process Monitoring
```bash
# Check if server is running
./loginserver.sh status
# Monitor resource usage
watch -n 1 './loginserver.sh status'
```
## Support
For issues and support:
- Check the server logs in `Logs/` directory
- Verify configuration in `LogIn.ini`
- Test database connectivity
- Check network connectivity and firewall settings
## Version Information
- **Server Version**: Knight Online Login Server v1.0
- **Platform**: Linux (Ubuntu/CentOS/Debian compatible)
- **Build System**: CMake 3.10+
- **Compiler**: GCC 7+
- **Dependencies**: ODBC, pthread
+248
View File
@@ -0,0 +1,248 @@
#!/bin/bash
# Knight Online Login Server Build Script for Linux
# Author: Levent Ferrah
# Set script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
BUILD_DIR="build"
JOBS=$(nproc)
# Functions
log_message() {
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
log_error() {
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1"
}
log_success() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] SUCCESS:${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1"
}
# Check dependencies
check_dependencies() {
log_message "Checking build dependencies..."
# Check for cmake
if ! command -v cmake &> /dev/null; then
log_error "cmake is not installed"
echo "Please install cmake: sudo apt-get install cmake"
return 1
fi
# Check for g++
if ! command -v g++ &> /dev/null; then
log_error "g++ is not installed"
echo "Please install g++: sudo apt-get install g++ build-essential"
return 1
fi
# Check for ODBC
if ! pkg-config --exists odbc &> /dev/null; then
log_warning "ODBC development files might not be installed"
echo "Consider installing: sudo apt-get install unixodbc-dev"
fi
log_success "Dependencies check completed"
return 0
}
# Clean build directory
clean_build() {
log_message "Cleaning build directory..."
if [ -d "$BUILD_DIR" ]; then
rm -rf "$BUILD_DIR"
log_success "Build directory cleaned"
fi
}
# Build project
build_project() {
log_message "Starting build process..."
# Create build directory
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
# Configure with cmake
log_message "Configuring project with CMake..."
if ! cmake ..; then
log_error "CMake configuration failed"
return 1
fi
# Build project
log_message "Building project with $JOBS parallel jobs..."
if ! make -j$JOBS; then
log_error "Build failed"
return 1
fi
cd ..
log_success "Build completed successfully"
return 0
}
# Install project
install_project() {
log_message "Installing project..."
# Create bin directory if it doesn't exist
mkdir -p bin
# Copy binary
if [ -f "$BUILD_DIR/bin/LoginServer" ]; then
cp "$BUILD_DIR/bin/LoginServer" bin/
chmod +x bin/LoginServer
log_success "LoginServer binary installed to bin/"
else
log_error "LoginServer binary not found in build directory"
return 1
fi
# Make scripts executable
chmod +x loginserver.sh
log_success "Scripts made executable"
return 0
}
# Show usage
show_usage() {
echo "Knight Online Login Server Build Script"
echo ""
echo "Usage: $0 [OPTIONS] [COMMAND]"
echo ""
echo "Commands:"
echo " build - Build the project (default)"
echo " clean - Clean build directory"
echo " rebuild - Clean and build"
echo " install - Install built binaries"
echo " all - Clean, build, and install"
echo ""
echo "Options:"
echo " -h, --help - Show this help message"
echo " -j, --jobs N - Use N parallel jobs (default: $JOBS)"
echo ""
echo "Examples:"
echo " $0 # Build project"
echo " $0 clean # Clean build files"
echo " $0 rebuild # Clean and rebuild"
echo " $0 all # Full build and install"
echo " $0 -j 4 build # Build with 4 parallel jobs"
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_usage
exit 0
;;
-j|--jobs)
JOBS="$2"
shift 2
;;
clean)
COMMAND="clean"
shift
;;
build)
COMMAND="build"
shift
;;
rebuild)
COMMAND="rebuild"
shift
;;
install)
COMMAND="install"
shift
;;
all)
COMMAND="all"
shift
;;
*)
log_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Default command
if [ -z "$COMMAND" ]; then
COMMAND="build"
fi
# Main execution
log_message "Knight Online Login Server Build Script"
log_message "Build command: $COMMAND"
log_message "Parallel jobs: $JOBS"
echo ""
case "$COMMAND" in
clean)
clean_build
;;
build)
if ! check_dependencies; then
exit 1
fi
if ! build_project; then
exit 1
fi
;;
rebuild)
if ! check_dependencies; then
exit 1
fi
clean_build
if ! build_project; then
exit 1
fi
;;
install)
if ! install_project; then
exit 1
fi
;;
all)
if ! check_dependencies; then
exit 1
fi
clean_build
if ! build_project; then
exit 1
fi
if ! install_project; then
exit 1
fi
log_success "Build and installation completed successfully!"
echo ""
echo "To start the server:"
echo " ./loginserver.sh start"
echo ""
echo "To check server status:"
echo " ./loginserver.sh status"
;;
esac
exit 0
File diff suppressed because it is too large Load Diff
+251
View File
@@ -0,0 +1,251 @@
#!/bin/bash
# Knight Online Login Server Linux Startup Script
# Author: Levent Ferrah
# Description: Startup script for Knight Online Login Server on Linux
# Set script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Configuration
SERVER_NAME="LoginServer"
BINARY_PATH="./bin/LoginServer"
LOG_DIR="./Logs"
PID_FILE="./loginserver.pid"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Functions
log_message() {
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
log_error() {
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1"
}
log_success() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] SUCCESS:${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1"
}
# Check if server is running
is_running() {
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p $PID > /dev/null 2>&1; then
return 0
else
rm -f "$PID_FILE"
return 1
fi
fi
return 1
}
# Start server
start_server() {
log_message "Starting Knight Online Login Server..."
if is_running; then
log_warning "Login Server is already running (PID: $(cat $PID_FILE))"
return 1
fi
# Check if binary exists
if [ ! -f "$BINARY_PATH" ]; then
log_error "Binary not found: $BINARY_PATH"
log_message "Please compile the server first using: ./build.sh"
return 1
fi
# Create log directory
mkdir -p "$LOG_DIR"
# Check configuration file
if [ ! -f "./LogIn.ini" ]; then
log_warning "Configuration file LogIn.ini not found!"
log_message "Creating default configuration..."
create_default_config
fi
# Start server in background
nohup "$BINARY_PATH" > "$LOG_DIR/server_output.log" 2>&1 &
SERVER_PID=$!
# Save PID
echo $SERVER_PID > "$PID_FILE"
# Wait a moment and check if it started successfully
sleep 2
if is_running; then
log_success "Login Server started successfully (PID: $SERVER_PID)"
log_message "Server output: $LOG_DIR/server_output.log"
return 0
else
log_error "Failed to start Login Server"
return 1
fi
}
# Stop server
stop_server() {
log_message "Stopping Knight Online Login Server..."
if ! is_running; then
log_warning "Login Server is not running"
return 1
fi
PID=$(cat "$PID_FILE")
log_message "Sending SIGTERM to process $PID..."
kill -TERM $PID
# Wait for graceful shutdown
for i in {1..10}; do
if ! is_running; then
log_success "Login Server stopped successfully"
rm -f "$PID_FILE"
return 0
fi
sleep 1
done
# Force kill if necessary
log_warning "Graceful shutdown failed, forcing kill..."
kill -KILL $PID 2>/dev/null
rm -f "$PID_FILE"
log_success "Login Server forcefully stopped"
}
# Restart server
restart_server() {
log_message "Restarting Knight Online Login Server..."
stop_server
sleep 2
start_server
}
# Show server status
status_server() {
if is_running; then
PID=$(cat "$PID_FILE")
log_success "Login Server is running (PID: $PID)"
# Show some process info
echo ""
echo "Process Information:"
ps -p $PID -o pid,ppid,cmd,start,etime
# Show listening ports
echo ""
echo "Listening Ports:"
ss -tlnp | grep $PID 2>/dev/null || echo "No listening ports found"
else
log_error "Login Server is not running"
fi
}
# View logs
view_logs() {
if [ -f "$LOG_DIR/server_output.log" ]; then
tail -f "$LOG_DIR/server_output.log"
else
log_error "Log file not found: $LOG_DIR/server_output.log"
fi
}
# Create default configuration
create_default_config() {
cat > LogIn.ini << EOF
[DOWNLOAD]
URL=ftp.yoursite.net
PATH=/
[ODBC]
DSN=KO_MAIN
UID=username
PWD=password
[SETTINGS]
PORT=15100
[SERVER_LIST]
COUNT=1
SERVER_00=127.0.0.1
LANIP_00=127.0.0.1
NAME_00=Test Server
ID_00=1
GROUPID_00=1
PREMLIMIT_00=1000
FREELIMIT_00=1000
KING1_00=
KING2_00=
KINGMSG1_00=
KINGMSG2_00=
[NEWS]
TITLE_00=Welcome to Knight Online
MESSAGE_00=Welcome to our Knight Online server!
TITLE_01=
MESSAGE_01=
TITLE_02=
MESSAGE_02=
EOF
log_success "Default configuration created: LogIn.ini"
}
# Main script
case "$1" in
start)
start_server
;;
stop)
stop_server
;;
restart)
restart_server
;;
status)
status_server
;;
logs)
view_logs
;;
config)
create_default_config
;;
*)
echo "Knight Online Login Server Management Script"
echo ""
echo "Usage: $0 {start|stop|restart|status|logs|config}"
echo ""
echo "Commands:"
echo " start - Start the login server"
echo " stop - Stop the login server"
echo " restart - Restart the login server"
echo " status - Show server status"
echo " logs - View server logs (real-time)"
echo " config - Create default configuration file"
echo ""
echo "Examples:"
echo " $0 start # Start the server"
echo " $0 status # Check if server is running"
echo " $0 logs # Watch server logs"
echo ""
exit 1
;;
esac
exit $?
+13
View File
@@ -5,13 +5,19 @@ LoginServer * g_pMain;
static Condition s_hEvent;
bool g_bRunning = true;
#ifdef _WIN32
BOOL WINAPI _ConsoleHandler(DWORD dwCtrlType);
#endif
int main()
{
#ifdef _WIN32
SetConsoleTitle("Login Server Knight v" STRINGIFY(__VERSION));
// Override the console handler
SetConsoleCtrlHandler(_ConsoleHandler, TRUE);
#else
printf("Login Server Knight v%s\n", STRINGIFY(__VERSION));
#endif
HookSignals(&s_hEvent);
@@ -27,7 +33,12 @@ int main()
}
else
{
#ifdef _WIN32
system("pause");
#else
printf("Press Enter to continue...");
getchar();
#endif
}
printf("Server shutting down, please wait...\n");
@@ -39,6 +50,7 @@ int main()
return 0;
}
#ifdef _WIN32
BOOL WINAPI _ConsoleHandler(DWORD dwCtrlType)
{
s_hEvent.BeginSynchronized();
@@ -47,3 +59,4 @@ BOOL WINAPI _ConsoleHandler(DWORD dwCtrlType)
sleep(10000); // Win7 onwards allows 10 seconds before it'll forcibly terminate
return TRUE;
}
#endif
+197
View File
@@ -0,0 +1,197 @@
#pragma once
#ifndef _WIN32
// Linux-specific listen socket implementation
#include <sys/epoll.h>
#include <pthread.h>
template <class T>
class ListenSocket
{
public:
ListenSocket()
{
m_socket = -1;
m_epfd = -1;
m_shutdown = false;
m_socketMgr = nullptr;
}
// Constructor compatible with Windows version
ListenSocket(T * mgr, const char * hostname, uint32 port)
{
m_socket = -1;
m_epfd = -1;
m_shutdown = false;
m_socketMgr = mgr;
// Auto-open with default parameters
Open(port, hostname, 128, 65536, 65536);
}
~ListenSocket()
{
Close();
}
// Add IsOpen method for compatibility
bool IsOpen() const
{
return (m_socket != -1 && m_epfd != -1);
}
bool Open(uint32 port, const char * hostname, uint32 listenBacklogSize, uint32 sendBufferSize, uint32 recvBufferSize)
{
// Create socket
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
return false;
// Set socket options
int arg = 1;
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg));
// Set non-blocking
SocketOps::Nonblocking(m_socket);
// Disable buffering
SocketOps::DisableBuffering(m_socket);
// Bind socket
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
if (hostname && strlen(hostname) > 0)
{
struct hostent * hostname_entry = gethostbyname(hostname);
if (hostname_entry == nullptr)
{
close(m_socket);
return false;
}
memcpy(&address.sin_addr.s_addr, hostname_entry->h_addr_list[0], hostname_entry->h_length);
}
else
{
address.sin_addr.s_addr = htonl(INADDR_ANY);
}
if (bind(m_socket, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR)
{
close(m_socket);
return false;
}
// Listen
if (listen(m_socket, listenBacklogSize) == SOCKET_ERROR)
{
close(m_socket);
return false;
}
// Create epoll instance
m_epfd = epoll_create1(0);
if (m_epfd == -1)
{
close(m_socket);
return false;
}
// Add listen socket to epoll
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = m_socket;
if (epoll_ctl(m_epfd, EPOLL_CTL_ADD, m_socket, &ev) == -1)
{
close(m_epfd);
close(m_socket);
return false;
}
return true;
}
void Close()
{
m_shutdown = true;
if (m_socket != INVALID_SOCKET)
{
SocketOps::CloseSocket(m_socket);
m_socket = INVALID_SOCKET;
}
if (m_epfd != -1)
{
close(m_epfd);
m_epfd = -1;
}
}
void SetSocketMgr(T * mgr)
{
m_socketMgr = mgr;
}
uint32 GetFileDescriptor() { return m_socket; }
void run()
{
const int MAX_EVENTS = 64;
struct epoll_event events[MAX_EVENTS];
struct sockaddr_in tempAddress;
socklen_t len;
while (!m_shutdown)
{
int nfds = epoll_wait(m_epfd, events, MAX_EVENTS, 100); // 100ms timeout
if (nfds == -1)
{
if (errno != EINTR)
break;
continue;
}
for (int i = 0; i < nfds; ++i)
{
if (events[i].data.fd == m_socket)
{
// New connection
len = sizeof(sockaddr_in);
int aSocket = accept(m_socket, (sockaddr*)&tempAddress, &len);
if (aSocket == INVALID_SOCKET)
continue;
Socket *socket = m_socketMgr->AssignSocket(aSocket);
if (socket == nullptr)
{
SocketOps::CloseSocket(aSocket);
continue;
}
socket->SetCompletionPort(m_epfd);
socket->Accept(&tempAddress);
}
}
}
}
static void* ListenThreadProcedure(void* lpParam)
{
ListenSocket<T> * ls = (ListenSocket<T> *)lpParam;
ls->run();
return nullptr;
}
private:
T * m_socketMgr;
int m_socket;
int m_epfd;
bool m_shutdown;
};
#endif // !_WIN32
+6 -1
View File
@@ -5,7 +5,12 @@
#include "SocketOps.h"
#include "Socket.h"
#include "SocketMgr.h"
#include "ListenSocketWin32.h"
#ifdef _WIN32
#include "ListenSocketWin32.h"
#else
#include "ListenSocketLinux.h"
#endif
#include "JvCryption.h"
#include "KOSocket.h"
+19 -3
View File
@@ -11,26 +11,42 @@ enum SocketIOEvent
class OverlappedStruct
{
public:
#ifdef _WIN32
OVERLAPPED m_overlap;
#else
// Linux equivalent using epoll data
struct {
unsigned long Internal;
unsigned long InternalHigh;
union {
struct {
unsigned long Offset;
unsigned long OffsetHigh;
};
void* Pointer;
};
int hEvent;
} m_overlap;
#endif
SocketIOEvent m_event;
Atomic<bool> m_inUse;
OverlappedStruct(SocketIOEvent ev) : m_event(ev)
{
memset(&m_overlap, 0, sizeof(OVERLAPPED));
memset(&m_overlap, 0, sizeof(m_overlap));
m_inUse = false;
};
OverlappedStruct()
{
memset(&m_overlap, 0, sizeof(OVERLAPPED));
memset(&m_overlap, 0, sizeof(m_overlap));
m_inUse = false;
}
INLINE void Reset(SocketIOEvent ev)
{
memset(&m_overlap, 0, sizeof(OVERLAPPED));
memset(&m_overlap, 0, sizeof(m_overlap));
m_event = ev;
}
+33 -1
View File
@@ -48,10 +48,14 @@ void SocketMgr::SpawnWorkerThreads()
if (m_bWorkerThreadsActive)
return;
#ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
int threadcount = 1;//si.dwNumberOfProcessors * 2;
#else
// Linux: get number of processors
int threadcount = 1; // For now, use single thread
#endif
m_bWorkerThreadsActive = true;
@@ -67,6 +71,7 @@ void SocketMgr::SpawnWorkerThreads()
uint32 THREADCALL SocketMgr::SocketWorkerThread(void * lpParam)
{
SocketMgr *socketMgr = (SocketMgr *)lpParam;
#ifdef _WIN32
HANDLE cp = socketMgr->GetCompletionPort();
DWORD len;
Socket * s = nullptr;
@@ -96,24 +101,45 @@ uint32 THREADCALL SocketMgr::SocketWorkerThread(void * lpParam)
//std::async(std::launch::async, ophandlers[ov->m_event], s, len);
}
#else
// Linux implementation - simple event loop
while (socketMgr->m_bWorkerThreadsActive)
{
// For Linux, we use epoll in ListenSocket, so this thread can just sleep
usleep(100000); // 100ms
}
#endif
return 0;
}
void SocketMgr::Initialise()
{
#ifdef _WIN32
m_completionPort = nullptr;
#else
m_completionPort = -1;
#endif
}
void SocketMgr::CreateCompletionPort()
{
#ifdef _WIN32
SetCompletionPort(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, (ULONG_PTR)0, 0));
#else
// Linux: create epoll instance
SetCompletionPort(epoll_create1(0));
#endif
}
void SocketMgr::SetupWinsock()
{
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2,0), &wsaData);
#else
// Linux: no socket initialization needed
#endif
}
void HandleReadComplete(Socket * s, uint32 len)
@@ -161,8 +187,10 @@ void SocketMgr::OnDisconnect(Socket *pSock)
void SocketMgr::ShutdownThreads()
{
#ifdef _WIN32
OverlappedStruct * ov = new OverlappedStruct(SOCKET_IO_THREAD_SHUTDOWN);
PostQueuedCompletionStatus(m_completionPort, 0, (ULONG_PTR)0, &ov->m_overlap);
#endif
m_bWorkerThreadsActive = false;
@@ -201,7 +229,11 @@ void SocketMgr::CleanupSockets()
s_cleanupThread.waitForExit();
}
#ifdef _WIN32
WSACleanup();
#else
// Linux: no socket cleanup needed
#endif
}
SocketMgr::~SocketMgr()
+81
View File
@@ -0,0 +1,81 @@
#include "stdafx.h"
#include "SocketOps.h"
namespace SocketOps
{
#ifdef _WIN32
// Windows implementation (existing)
SOCKET CreateTCPFileDescriptor()
{
return WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
}
bool Nonblocking(SOCKET fd)
{
unsigned long arg = 1;
return (ioctlsocket(fd, FIONBIO, &arg) == 0);
}
bool Blocking(SOCKET fd)
{
unsigned long arg = 0;
return (ioctlsocket(fd, FIONBIO, &arg) == 0);
}
bool DisableBuffering(SOCKET fd)
{
int arg = 1;
return (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&arg, sizeof(int)) == 0);
}
bool EnableBuffering(SOCKET fd)
{
int arg = 0;
return (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&arg, sizeof(int)) == 0);
}
void CloseSocket(SOCKET fd)
{
shutdown(fd, SD_BOTH);
closesocket(fd);
}
#else
// Linux implementation
SOCKET CreateTCPFileDescriptor()
{
return socket(AF_INET, SOCK_STREAM, 0);
}
bool Nonblocking(SOCKET fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) return false;
return (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
}
bool Blocking(SOCKET fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) return false;
return (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == 0);
}
bool DisableBuffering(SOCKET fd)
{
int arg = 1;
return (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &arg, sizeof(int)) == 0);
}
bool EnableBuffering(SOCKET fd)
{
int arg = 0;
return (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &arg, sizeof(int)) == 0);
}
void CloseSocket(SOCKET fd)
{
shutdown(fd, SHUT_RDWR);
close(fd);
}
#endif
}
+6
View File
@@ -11,7 +11,9 @@ void HookSignals(Condition * notifier)
signal(SIGINT, OnSignal);
signal(SIGTERM, OnSignal);
signal(SIGABRT, OnSignal);
#ifdef _WIN32
signal(SIGBREAK, OnSignal);
#endif
}
void OnSignal(int s)
@@ -21,7 +23,9 @@ void OnSignal(int s)
case SIGINT:
case SIGTERM:
case SIGABRT:
#ifdef _WIN32
case SIGBREAK:
#endif
g_hNotifier->BeginSynchronized();
g_hNotifier->Signal();
g_hNotifier->EndSynchronized();
@@ -36,5 +40,7 @@ void UnhookSignals()
signal(SIGINT, 0);
signal(SIGTERM, 0);
signal(SIGABRT, 0);
#ifdef _WIN32
signal(SIGBREAK, 0);
#endif
}
+125 -14
View File
@@ -2,19 +2,124 @@
#include <queue>
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#ifdef _WIN32
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define THREADCALL WINAPI
#define STRCASECMP _stricmp
#define THREADCALL WINAPI
#define STRCASECMP _stricmp
#define I64FMT "%016I64X"
#define I64FMTD "%I64u"
#define SI64FMTD "%I64d"
#define I64FMT "%016I64X"
#define I64FMTD "%I64u"
#define SI64FMTD "%I64d"
#else
// Linux includes
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <dirent.h>
#define THREADCALL
#define STRCASECMP strcasecmp
#define Sleep(ms) usleep((ms) * 1000)
#define CreateDirectory(path, attr) mkdir(path, 0755)
#define _snprintf snprintf
#define I64FMT "%016lX"
#define I64FMTD "%lu"
#define SI64FMTD "%ld"
// Windows types for Linux (define before any system headers)
typedef int BOOL;
#ifndef DWORD
typedef unsigned int DWORD; // Use int to match ODBC expectation
#endif
typedef int SOCKET;
typedef int HANDLE;
typedef void* LPVOID;
typedef unsigned long* LPDWORD;
#ifndef TCHAR
typedef char TCHAR;
#endif
#define TRUE 1
#define FALSE 0
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define INVALID_HANDLE_VALUE -1
// Windows socket functions mapping to Linux
#define WSASocket(af, type, protocol, lpProtocolInfo, g, dwFlags) socket(af, type, protocol)
#define WSAAccept(s, addr, addrlen, lpfnCondition, dwCallbackData) accept(s, addr, addrlen)
#define WSAGetLastError() errno
#define WSAStartup(ver, data) 0
#define WSACleanup() 0
#define closesocket(s) close(s)
#define ioctlsocket(s, cmd, argp) ioctl(s, cmd, argp)
#define SD_BOTH SHUT_RDWR
#define FIONBIO 1
#define MAKEWORD(low, high) ((unsigned short)(((unsigned char)(low)) | ((unsigned short)((unsigned char)(high))) << 8))
// Additional socket constants
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAECONNRESET ECONNRESET
#define WSAENOTCONN ENOTCONN
// Windows system functions
#define GetSystemInfo(si) memset(si, 0, sizeof(*si))
#define GetQueuedCompletionStatus(cp, len, key, ol, timeout) false
#define CreateIoCompletionPort(fd, cp, key, threads) -1
#define PostQueuedCompletionStatus(cp, bytes, key, ol) false
// System info structure
typedef struct {
unsigned long dwNumberOfProcessors;
} SYSTEM_INFO;
// WSA Data structure
typedef struct {
unsigned short wVersion;
unsigned short wHighVersion;
char szDescription[257];
char szSystemStatus[129];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char* lpVendorInfo;
} WSADATA;
// Additional types
typedef unsigned long ULONG_PTR;
// OVERLAPPED structure equivalent for Linux (using epoll)
typedef struct {
unsigned long Internal;
unsigned long InternalHigh;
union {
struct {
unsigned long Offset;
unsigned long OffsetHigh;
};
void* Pointer;
};
HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;
#define CONTAINING_RECORD(address, type, field) \
((type *)((char*)(address) - (char*)&(((type *)0)->field)))
#endif
#if defined(_DEBUG) || defined(DEBUG)
# include <cassert>
@@ -42,9 +147,11 @@
# define TRACE
#endif
// Ignore the warning "nonstandard extension used: enum '<enum name>' used in qualified name"
// Sometimes it's necessary to avoid collisions, but aside from that, specifying the enumeration helps make code intent clearer.
#pragma warning(disable: 4482)
#ifdef _WIN32
// Ignore the warning "nonstandard extension used: enum '<enum name>' used in qualified name"
// Sometimes it's necessary to avoid collisions, but aside from that, specifying the enumeration helps make code intent clearer.
#pragma warning(disable: 4482)
#endif
#define STR(str) #str
#define STRINGIFY(str) STR(str)
@@ -65,7 +172,11 @@ protected:
std::recursive_mutex& target;
};
#define sleep(ms) Sleep(ms)
#ifdef _WIN32
#define sleep(ms) Sleep(ms)
#else
#define sleep(ms) usleep((ms) * 1000)
#endif
#ifdef min
#undef min
+2
View File
@@ -8,7 +8,9 @@
#ifdef WIN32
#include <tchar.h>
#else
#ifndef TCHAR
#define TCHAR char
#endif
#define _T(x) x
#define _tprintf printf
#define _vsntprintf vsnprintf
+5 -1
View File
@@ -1,6 +1,10 @@
#pragma once
#define INLINE __forceinline
#ifdef _WIN32
#define INLINE __forceinline
#else
#define INLINE inline __attribute__((always_inline))
#endif
typedef int64_t int64;
typedef int32_t int32;