Compare commits
5
Commits
1b9b6c506d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5cbfbc916 | ||
|
|
e5a1ca68e7 | ||
|
|
59b331458c | ||
|
|
26a4c99c5c | ||
|
|
9fd7a9283c |
@@ -1,7 +1,25 @@
|
|||||||
# knightonline
|
# Knight Online
|
||||||
|
1.0.0
|
||||||
|
## License
|
||||||
|
|
||||||
<<<<<<< HEAD
|
MIT License
|
||||||
Knight Online Clone Project v1.0
|
|
||||||
=======
|
Copyright (c) 2024 Knight Online
|
||||||
Knight Online Clone Project
|
|
||||||
>>>>>>> 191661329532817bf0e8da163c8ac248afc0cddd
|
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.
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -20,7 +20,11 @@ bool LoginServer::Startup()
|
|||||||
printf("Project : %d\n", GetVersion());
|
printf("Project : %d\n", GetVersion());
|
||||||
printf("Edited by Levent\n\n");
|
printf("Edited by Levent\n\n");
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
CreateDirectory("Logs",NULL);
|
CreateDirectory("Logs",NULL);
|
||||||
|
#else
|
||||||
|
mkdir("Logs", 0755);
|
||||||
|
#endif
|
||||||
|
|
||||||
m_fpLoginServer = fopen("./Logs/LoginServer.log", "a");
|
m_fpLoginServer = fopen("./Logs/LoginServer.log", "a");
|
||||||
if (m_fpLoginServer == nullptr)
|
if (m_fpLoginServer == nullptr)
|
||||||
|
|||||||
@@ -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);
|
Send(&result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
@@ -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 $?
|
||||||
@@ -5,13 +5,19 @@ LoginServer * g_pMain;
|
|||||||
static Condition s_hEvent;
|
static Condition s_hEvent;
|
||||||
bool g_bRunning = true;
|
bool g_bRunning = true;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
BOOL WINAPI _ConsoleHandler(DWORD dwCtrlType);
|
BOOL WINAPI _ConsoleHandler(DWORD dwCtrlType);
|
||||||
|
#endif
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
SetConsoleTitle("Login Server Knight v" STRINGIFY(__VERSION));
|
SetConsoleTitle("Login Server Knight v" STRINGIFY(__VERSION));
|
||||||
// Override the console handler
|
// Override the console handler
|
||||||
SetConsoleCtrlHandler(_ConsoleHandler, TRUE);
|
SetConsoleCtrlHandler(_ConsoleHandler, TRUE);
|
||||||
|
#else
|
||||||
|
printf("Login Server Knight v%s\n", STRINGIFY(__VERSION));
|
||||||
|
#endif
|
||||||
|
|
||||||
HookSignals(&s_hEvent);
|
HookSignals(&s_hEvent);
|
||||||
|
|
||||||
@@ -27,7 +33,12 @@ int main()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
system("pause");
|
system("pause");
|
||||||
|
#else
|
||||||
|
printf("Press Enter to continue...");
|
||||||
|
getchar();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Server shutting down, please wait...\n");
|
printf("Server shutting down, please wait...\n");
|
||||||
@@ -39,6 +50,7 @@ int main()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
BOOL WINAPI _ConsoleHandler(DWORD dwCtrlType)
|
BOOL WINAPI _ConsoleHandler(DWORD dwCtrlType)
|
||||||
{
|
{
|
||||||
s_hEvent.BeginSynchronized();
|
s_hEvent.BeginSynchronized();
|
||||||
@@ -47,3 +59,4 @@ BOOL WINAPI _ConsoleHandler(DWORD dwCtrlType)
|
|||||||
sleep(10000); // Win7 onwards allows 10 seconds before it'll forcibly terminate
|
sleep(10000); // Win7 onwards allows 10 seconds before it'll forcibly terminate
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -5,7 +5,12 @@
|
|||||||
#include "SocketOps.h"
|
#include "SocketOps.h"
|
||||||
#include "Socket.h"
|
#include "Socket.h"
|
||||||
#include "SocketMgr.h"
|
#include "SocketMgr.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
#include "ListenSocketWin32.h"
|
#include "ListenSocketWin32.h"
|
||||||
|
#else
|
||||||
|
#include "ListenSocketLinux.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "JvCryption.h"
|
#include "JvCryption.h"
|
||||||
#include "KOSocket.h"
|
#include "KOSocket.h"
|
||||||
@@ -11,26 +11,42 @@ enum SocketIOEvent
|
|||||||
class OverlappedStruct
|
class OverlappedStruct
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
#ifdef _WIN32
|
||||||
OVERLAPPED m_overlap;
|
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;
|
SocketIOEvent m_event;
|
||||||
|
|
||||||
Atomic<bool> m_inUse;
|
Atomic<bool> m_inUse;
|
||||||
|
|
||||||
OverlappedStruct(SocketIOEvent ev) : m_event(ev)
|
OverlappedStruct(SocketIOEvent ev) : m_event(ev)
|
||||||
{
|
{
|
||||||
memset(&m_overlap, 0, sizeof(OVERLAPPED));
|
memset(&m_overlap, 0, sizeof(m_overlap));
|
||||||
m_inUse = false;
|
m_inUse = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
OverlappedStruct()
|
OverlappedStruct()
|
||||||
{
|
{
|
||||||
memset(&m_overlap, 0, sizeof(OVERLAPPED));
|
memset(&m_overlap, 0, sizeof(m_overlap));
|
||||||
m_inUse = false;
|
m_inUse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void Reset(SocketIOEvent ev)
|
INLINE void Reset(SocketIOEvent ev)
|
||||||
{
|
{
|
||||||
memset(&m_overlap, 0, sizeof(OVERLAPPED));
|
memset(&m_overlap, 0, sizeof(m_overlap));
|
||||||
m_event = ev;
|
m_event = ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,10 +48,14 @@ void SocketMgr::SpawnWorkerThreads()
|
|||||||
if (m_bWorkerThreadsActive)
|
if (m_bWorkerThreadsActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
SYSTEM_INFO si;
|
SYSTEM_INFO si;
|
||||||
GetSystemInfo(&si);
|
GetSystemInfo(&si);
|
||||||
|
|
||||||
int threadcount = 1;//si.dwNumberOfProcessors * 2;
|
int threadcount = 1;//si.dwNumberOfProcessors * 2;
|
||||||
|
#else
|
||||||
|
// Linux: get number of processors
|
||||||
|
int threadcount = 1; // For now, use single thread
|
||||||
|
#endif
|
||||||
|
|
||||||
m_bWorkerThreadsActive = true;
|
m_bWorkerThreadsActive = true;
|
||||||
|
|
||||||
@@ -67,6 +71,7 @@ void SocketMgr::SpawnWorkerThreads()
|
|||||||
uint32 THREADCALL SocketMgr::SocketWorkerThread(void * lpParam)
|
uint32 THREADCALL SocketMgr::SocketWorkerThread(void * lpParam)
|
||||||
{
|
{
|
||||||
SocketMgr *socketMgr = (SocketMgr *)lpParam;
|
SocketMgr *socketMgr = (SocketMgr *)lpParam;
|
||||||
|
#ifdef _WIN32
|
||||||
HANDLE cp = socketMgr->GetCompletionPort();
|
HANDLE cp = socketMgr->GetCompletionPort();
|
||||||
DWORD len;
|
DWORD len;
|
||||||
Socket * s = nullptr;
|
Socket * s = nullptr;
|
||||||
@@ -96,24 +101,45 @@ uint32 THREADCALL SocketMgr::SocketWorkerThread(void * lpParam)
|
|||||||
//std::async(std::launch::async, ophandlers[ov->m_event], s, len);
|
//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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketMgr::Initialise()
|
void SocketMgr::Initialise()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
m_completionPort = nullptr;
|
m_completionPort = nullptr;
|
||||||
|
#else
|
||||||
|
m_completionPort = -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketMgr::CreateCompletionPort()
|
void SocketMgr::CreateCompletionPort()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
SetCompletionPort(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, (ULONG_PTR)0, 0));
|
SetCompletionPort(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, (ULONG_PTR)0, 0));
|
||||||
|
#else
|
||||||
|
// Linux: create epoll instance
|
||||||
|
SetCompletionPort(epoll_create1(0));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketMgr::SetupWinsock()
|
void SocketMgr::SetupWinsock()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
WSAStartup(MAKEWORD(2,0), &wsaData);
|
WSAStartup(MAKEWORD(2,0), &wsaData);
|
||||||
|
#else
|
||||||
|
// Linux: no socket initialization needed
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleReadComplete(Socket * s, uint32 len)
|
void HandleReadComplete(Socket * s, uint32 len)
|
||||||
@@ -161,8 +187,10 @@ void SocketMgr::OnDisconnect(Socket *pSock)
|
|||||||
|
|
||||||
void SocketMgr::ShutdownThreads()
|
void SocketMgr::ShutdownThreads()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
OverlappedStruct * ov = new OverlappedStruct(SOCKET_IO_THREAD_SHUTDOWN);
|
OverlappedStruct * ov = new OverlappedStruct(SOCKET_IO_THREAD_SHUTDOWN);
|
||||||
PostQueuedCompletionStatus(m_completionPort, 0, (ULONG_PTR)0, &ov->m_overlap);
|
PostQueuedCompletionStatus(m_completionPort, 0, (ULONG_PTR)0, &ov->m_overlap);
|
||||||
|
#endif
|
||||||
|
|
||||||
m_bWorkerThreadsActive = false;
|
m_bWorkerThreadsActive = false;
|
||||||
|
|
||||||
@@ -201,7 +229,11 @@ void SocketMgr::CleanupSockets()
|
|||||||
s_cleanupThread.waitForExit();
|
s_cleanupThread.waitForExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
#else
|
||||||
|
// Linux: no socket cleanup needed
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketMgr::~SocketMgr()
|
SocketMgr::~SocketMgr()
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -11,7 +11,9 @@ void HookSignals(Condition * notifier)
|
|||||||
signal(SIGINT, OnSignal);
|
signal(SIGINT, OnSignal);
|
||||||
signal(SIGTERM, OnSignal);
|
signal(SIGTERM, OnSignal);
|
||||||
signal(SIGABRT, OnSignal);
|
signal(SIGABRT, OnSignal);
|
||||||
|
#ifdef _WIN32
|
||||||
signal(SIGBREAK, OnSignal);
|
signal(SIGBREAK, OnSignal);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSignal(int s)
|
void OnSignal(int s)
|
||||||
@@ -21,7 +23,9 @@ void OnSignal(int s)
|
|||||||
case SIGINT:
|
case SIGINT:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
case SIGABRT:
|
case SIGABRT:
|
||||||
|
#ifdef _WIN32
|
||||||
case SIGBREAK:
|
case SIGBREAK:
|
||||||
|
#endif
|
||||||
g_hNotifier->BeginSynchronized();
|
g_hNotifier->BeginSynchronized();
|
||||||
g_hNotifier->Signal();
|
g_hNotifier->Signal();
|
||||||
g_hNotifier->EndSynchronized();
|
g_hNotifier->EndSynchronized();
|
||||||
@@ -36,5 +40,7 @@ void UnhookSignals()
|
|||||||
signal(SIGINT, 0);
|
signal(SIGINT, 0);
|
||||||
signal(SIGTERM, 0);
|
signal(SIGTERM, 0);
|
||||||
signal(SIGABRT, 0);
|
signal(SIGABRT, 0);
|
||||||
|
#ifdef _WIN32
|
||||||
signal(SIGBREAK, 0);
|
signal(SIGBREAK, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
#define VC_EXTRALEAN
|
#define VC_EXTRALEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
@@ -15,6 +16,110 @@
|
|||||||
#define I64FMT "%016I64X"
|
#define I64FMT "%016I64X"
|
||||||
#define I64FMTD "%I64u"
|
#define I64FMTD "%I64u"
|
||||||
#define SI64FMTD "%I64d"
|
#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)
|
#if defined(_DEBUG) || defined(DEBUG)
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
@@ -42,9 +147,11 @@
|
|||||||
# define TRACE
|
# define TRACE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
// Ignore the warning "nonstandard extension used: enum '<enum name>' used in qualified name"
|
// 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.
|
// Sometimes it's necessary to avoid collisions, but aside from that, specifying the enumeration helps make code intent clearer.
|
||||||
#pragma warning(disable: 4482)
|
#pragma warning(disable: 4482)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STR(str) #str
|
#define STR(str) #str
|
||||||
#define STRINGIFY(str) STR(str)
|
#define STRINGIFY(str) STR(str)
|
||||||
@@ -65,7 +172,11 @@ protected:
|
|||||||
std::recursive_mutex& target;
|
std::recursive_mutex& target;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
#define sleep(ms) Sleep(ms)
|
#define sleep(ms) Sleep(ms)
|
||||||
|
#else
|
||||||
|
#define sleep(ms) usleep((ms) * 1000)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef min
|
#ifdef min
|
||||||
#undef min
|
#undef min
|
||||||
|
|||||||
@@ -8,7 +8,9 @@
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#else
|
#else
|
||||||
|
#ifndef TCHAR
|
||||||
#define TCHAR char
|
#define TCHAR char
|
||||||
|
#endif
|
||||||
#define _T(x) x
|
#define _T(x) x
|
||||||
#define _tprintf printf
|
#define _tprintf printf
|
||||||
#define _vsntprintf vsnprintf
|
#define _vsntprintf vsnprintf
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
#define INLINE __forceinline
|
#define INLINE __forceinline
|
||||||
|
#else
|
||||||
|
#define INLINE inline __attribute__((always_inline))
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef int64_t int64;
|
typedef int64_t int64;
|
||||||
typedef int32_t int32;
|
typedef int32_t int32;
|
||||||
|
|||||||
Reference in New Issue
Block a user