mirror of
https://github.com/wiiu-env/wut.git
synced 2025-02-02 21:32:35 +01:00
Add tools readrpl, udplogserver.
This commit is contained in:
parent
959e4897c1
commit
9bcf22e40f
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
|||||||
[submodule "tools/libraries/fmt"]
|
[submodule "tools/libraries/fmt"]
|
||||||
path = tools/libraries/fmt
|
path = tools/libraries/fmt
|
||||||
url = https://github.com/fmtlib/fmt.git
|
url = https://github.com/fmtlib/fmt.git
|
||||||
|
[submodule "tools/libraries/excmd"]
|
||||||
|
path = tools/libraries/excmd
|
||||||
|
url = https://github.com/exjam/excmd.git
|
||||||
|
@ -44,6 +44,6 @@ script:
|
|||||||
- cd ../
|
- cd ../
|
||||||
- cd samples/helloworld
|
- cd samples/helloworld
|
||||||
- mkdir build && cd build
|
- mkdir build && cd build
|
||||||
- chmod +x $WUT_ROOT/bin/wut-elf2rpl
|
- chmod +x $WUT_ROOT/bin/elf2rpl
|
||||||
- cmake -DCMAKE_TOOLCHAIN_FILE=$WUT_ROOT/share/wut.toolchain.cmake -DCMAKE_INSTALL_PREFIX=$WUT_ROOT/samples ../
|
- cmake -DCMAKE_TOOLCHAIN_FILE=$WUT_ROOT/share/wut.toolchain.cmake -DCMAKE_INSTALL_PREFIX=$WUT_ROOT/samples ../
|
||||||
- make -j4 VERBOSE=TRUE install
|
- make -j4 VERBOSE=TRUE install
|
||||||
|
@ -32,7 +32,7 @@ externalproject_add(tools
|
|||||||
externalproject_get_property(tools BINARY_DIR)
|
externalproject_get_property(tools BINARY_DIR)
|
||||||
set(TOOLS_BINARY_DIR ${BINARY_DIR})
|
set(TOOLS_BINARY_DIR ${BINARY_DIR})
|
||||||
|
|
||||||
set(WUT_RPLGEN "${TOOLS_BINARY_DIR}/bin/wut-rplgen")
|
set(WUT_RPLGEN "${TOOLS_BINARY_DIR}/bin/rplgen")
|
||||||
|
|
||||||
externalproject_add(cafe
|
externalproject_add(cafe
|
||||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cafe"
|
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cafe"
|
||||||
|
@ -35,7 +35,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
|||||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||||
|
|
||||||
# Tools
|
# Tools
|
||||||
set(WUT_ELF2RPL "${WUT_ROOT}/bin/wut-elf2rpl${CMAKE_EXECUTABLE_SUFFIX}" CACHE PATH "")
|
set(WUT_ELF2RPL "${WUT_ROOT}/bin/elf2rpl${CMAKE_EXECUTABLE_SUFFIX}" CACHE PATH "")
|
||||||
|
|
||||||
# Flags
|
# Flags
|
||||||
set(WUT TRUE)
|
set(WUT TRUE)
|
||||||
|
@ -18,4 +18,6 @@ find_package(ZLIB REQUIRED)
|
|||||||
|
|
||||||
include_directories(common)
|
include_directories(common)
|
||||||
add_subdirectory(elf2rpl)
|
add_subdirectory(elf2rpl)
|
||||||
|
add_subdirectory(readrpl)
|
||||||
add_subdirectory(rplgen)
|
add_subdirectory(rplgen)
|
||||||
|
add_subdirectory(udplogserver)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "type_traits.h"
|
#include "type_traits.h"
|
||||||
#include <fmt/ostream.h>
|
#include <utility>
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
class be_val
|
class be_val
|
||||||
@ -391,29 +391,6 @@ public:
|
|||||||
return value().operator ->();
|
return value().operator ->();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to access FunctionPointer::getAddress
|
|
||||||
template<typename K = value_type>
|
|
||||||
auto getAddress()
|
|
||||||
-> decltype(std::declval<const K>().getAddress()) const
|
|
||||||
{
|
|
||||||
return value().getAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to access Pointer::getRawPointer
|
|
||||||
template<typename K = value_type>
|
|
||||||
auto getRawPointer()
|
|
||||||
-> decltype(std::declval<const K>().getRawPointer()) const
|
|
||||||
{
|
|
||||||
return value().getRawPointer();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Please use virt_addrof or phys_addrof instead
|
|
||||||
auto operator &() = delete;
|
|
||||||
|
|
||||||
friend std::ostream &operator<<(std::ostream &os, const be_val &b) {
|
|
||||||
return os << b.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type mStorage;
|
value_type mStorage;
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
add_executable(wut-elf2rpl main.cpp)
|
project(elf2rpl)
|
||||||
target_include_directories(wut-elf2rpl PRIVATE
|
|
||||||
|
file(GLOB_RECURSE SOURCE_FILES *.cpp)
|
||||||
|
file(GLOB_RECURSE HEADER_FILES *.h)
|
||||||
|
|
||||||
|
add_executable(elf2rpl
|
||||||
|
${SOURCE_FILES} ${HEADER_FILES})
|
||||||
|
|
||||||
|
target_include_directories(elf2rpl PRIVATE
|
||||||
${ZLIB_INCLUDE_DIR})
|
${ZLIB_INCLUDE_DIR})
|
||||||
target_link_libraries(wut-elf2rpl
|
|
||||||
|
target_link_libraries(elf2rpl
|
||||||
fmt
|
fmt
|
||||||
${ZLIB_LIBRARIES})
|
${ZLIB_LIBRARIES})
|
||||||
|
|
||||||
install(TARGETS wut-elf2rpl RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
install(TARGETS elf2rpl RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
||||||
|
@ -1 +1,6 @@
|
|||||||
|
# excmd
|
||||||
|
add_library(excmd INTERFACE)
|
||||||
|
target_include_directories(excmd INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/excmd/src")
|
||||||
|
|
||||||
|
# fmt
|
||||||
add_subdirectory(fmt)
|
add_subdirectory(fmt)
|
||||||
|
1
tools/libraries/excmd
Submodule
1
tools/libraries/excmd
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b48dab4954bdc074d7768e38065171441aaff7ce
|
17
tools/readrpl/CMakeLists.txt
Normal file
17
tools/readrpl/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
project(readrpl)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SOURCE_FILES *.cpp)
|
||||||
|
file(GLOB_RECURSE HEADER_FILES *.h)
|
||||||
|
|
||||||
|
add_executable(readrpl
|
||||||
|
${SOURCE_FILES} ${HEADER_FILES})
|
||||||
|
|
||||||
|
target_include_directories(readrpl PRIVATE
|
||||||
|
${ZLIB_INCLUDE_DIR})
|
||||||
|
|
||||||
|
target_link_libraries(readrpl
|
||||||
|
excmd
|
||||||
|
fmt
|
||||||
|
${ZLIB_LIBRARIES})
|
||||||
|
|
||||||
|
install(TARGETS readrpl RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
736
tools/readrpl/main.cpp
Normal file
736
tools/readrpl/main.cpp
Normal file
@ -0,0 +1,736 @@
|
|||||||
|
#include <excmd.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <zlib.h>
|
||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
struct Section
|
||||||
|
{
|
||||||
|
elf::SectionHeader header;
|
||||||
|
std::vector<char> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatET(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::ET_NONE:
|
||||||
|
return "ET_NONE";
|
||||||
|
case elf::ET_REL:
|
||||||
|
return "ET_REL";
|
||||||
|
case elf::ET_EXEC:
|
||||||
|
return "ET_EXEC";
|
||||||
|
case elf::ET_DYN:
|
||||||
|
return "ET_DYN";
|
||||||
|
case elf::ET_CORE:
|
||||||
|
return "ET_CORE";
|
||||||
|
case elf::ET_CAFE_RPL:
|
||||||
|
return "ET_CAFE_RPL";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatEM(uint32_t machine)
|
||||||
|
{
|
||||||
|
switch (machine) {
|
||||||
|
case elf::EM_PPC:
|
||||||
|
return "EM_PPC";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatEABI(uint32_t machine)
|
||||||
|
{
|
||||||
|
switch (machine) {
|
||||||
|
case elf::EABI_CAFE:
|
||||||
|
return "EABI_CAFE";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSHF(uint32_t flags)
|
||||||
|
{
|
||||||
|
std::string result = "";
|
||||||
|
|
||||||
|
if (flags & elf::SHF_WRITE) {
|
||||||
|
result += "W";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & elf::SHF_ALLOC) {
|
||||||
|
result += "A";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & elf::SHF_EXECINSTR) {
|
||||||
|
result += "X";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & elf::SHF_DEFLATED) {
|
||||||
|
result += "Z";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSHT(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::SHT_NULL:
|
||||||
|
return "SHT_NULL";
|
||||||
|
case elf::SHT_PROGBITS:
|
||||||
|
return "SHT_PROGBITS";
|
||||||
|
case elf::SHT_SYMTAB:
|
||||||
|
return "SHT_SYMTAB";
|
||||||
|
case elf::SHT_STRTAB:
|
||||||
|
return "SHT_STRTAB";
|
||||||
|
case elf::SHT_RELA:
|
||||||
|
return "SHT_RELA";
|
||||||
|
case elf::SHT_HASH:
|
||||||
|
return "SHT_HASH";
|
||||||
|
case elf::SHT_DYNAMIC:
|
||||||
|
return "SHT_DYNAMIC";
|
||||||
|
case elf::SHT_NOTE:
|
||||||
|
return "SHT_NOTE";
|
||||||
|
case elf::SHT_NOBITS:
|
||||||
|
return "SHT_NOBITS";
|
||||||
|
case elf::SHT_REL:
|
||||||
|
return "SHT_REL";
|
||||||
|
case elf::SHT_SHLIB:
|
||||||
|
return "SHT_SHLIB";
|
||||||
|
case elf::SHT_DYNSYM:
|
||||||
|
return "SHT_DYNSYM";
|
||||||
|
case elf::SHT_INIT_ARRAY:
|
||||||
|
return "SHT_INIT_ARRAY";
|
||||||
|
case elf::SHT_FINI_ARRAY:
|
||||||
|
return "SHT_FINI_ARRAY";
|
||||||
|
case elf::SHT_PREINIT_ARRAY:
|
||||||
|
return "SHT_PREINIT_ARRAY";
|
||||||
|
case elf::SHT_GROUP:
|
||||||
|
return "SHT_GROUP";
|
||||||
|
case elf::SHT_SYMTAB_SHNDX:
|
||||||
|
return "SHT_SYMTAB_SHNDX";
|
||||||
|
case elf::SHT_LOPROC:
|
||||||
|
return "SHT_LOPROC";
|
||||||
|
case elf::SHT_HIPROC:
|
||||||
|
return "SHT_HIPROC";
|
||||||
|
case elf::SHT_LOUSER:
|
||||||
|
return "SHT_LOUSER";
|
||||||
|
case elf::SHT_RPL_EXPORTS:
|
||||||
|
return "SHT_RPL_EXPORTS";
|
||||||
|
case elf::SHT_RPL_IMPORTS:
|
||||||
|
return "SHT_RPL_IMPORTS";
|
||||||
|
case elf::SHT_RPL_CRCS:
|
||||||
|
return "SHT_RPL_CRCS";
|
||||||
|
case elf::SHT_RPL_FILEINFO:
|
||||||
|
return "SHT_RPL_FILEINFO";
|
||||||
|
case elf::SHT_HIUSER:
|
||||||
|
return "SHT_HIUSER";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printHeader(elf::Header &header)
|
||||||
|
{
|
||||||
|
fmt::print("ElfHeader\n");
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "magic", header.magic);
|
||||||
|
fmt::print(" {:<20} = {}\n", "fileClass", header.fileClass);
|
||||||
|
fmt::print(" {:<20} = {}\n", "encoding", header.encoding);
|
||||||
|
fmt::print(" {:<20} = {}\n", "elfVersion", header.elfVersion);
|
||||||
|
fmt::print(" {:<20} = {} 0x{:04x}\n", "abi", formatEABI(header.abi), header.abi);
|
||||||
|
fmt::print(" {:<20} = {} 0x{:04X}\n", "type", formatET(header.type), header.type);
|
||||||
|
fmt::print(" {:<20} = {} {}\n", "machine", formatEM(header.machine), header.machine);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "version", header.version);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "entry", header.entry);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "phoff", header.phoff);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "shoff", header.shoff);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "flags", header.flags);
|
||||||
|
fmt::print(" {:<20} = {}\n", "ehsize", header.ehsize);
|
||||||
|
fmt::print(" {:<20} = {}\n", "phentsize", header.phentsize);
|
||||||
|
fmt::print(" {:<20} = {}\n", "phnum", header.phnum);
|
||||||
|
fmt::print(" {:<20} = {}\n", "shentsize", header.shentsize);
|
||||||
|
fmt::print(" {:<20} = {}\n", "shnum", header.shnum);
|
||||||
|
fmt::print(" {:<20} = {}\n", "shstrndx", header.shstrndx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printSectionSummary(std::vector<Section> §ions,
|
||||||
|
const char *shStrTab)
|
||||||
|
{
|
||||||
|
fmt::print("Sections:\n");
|
||||||
|
fmt::print(
|
||||||
|
" {:<4} {:<20} {:<16} {:<8} {:<6} {:<6} {:<2} {:<4} {:<2} {:<4} {:<5}\n",
|
||||||
|
"[Nr]", "Name", "Type", "Addr", "Off", "Size", "ES", "Flag", "Lk", "Info", "Align");
|
||||||
|
|
||||||
|
for (auto i = 0u; i < sections.size(); ++i) {
|
||||||
|
auto §ion = sections[i];
|
||||||
|
auto name = shStrTab + section.header.name;
|
||||||
|
auto type = formatSHT(section.header.type);
|
||||||
|
auto flags = formatSHF(section.header.flags);
|
||||||
|
|
||||||
|
fmt::print(
|
||||||
|
" [{:>2}] {:<20} {:<16} {:08X} {:06X} {:06X} {:02X} {:>4} {:>2} {:>4} {:>5}\n",
|
||||||
|
i,
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
static_cast<uint32_t>(section.header.addr),
|
||||||
|
section.header.offset,
|
||||||
|
section.header.size,
|
||||||
|
section.header.entsize,
|
||||||
|
flags,
|
||||||
|
section.header.link,
|
||||||
|
section.header.info,
|
||||||
|
section.header.addralign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printFileInfo(Section §ion)
|
||||||
|
{
|
||||||
|
auto &info = *reinterpret_cast<elf::RplFileInfo *>(section.data.data());
|
||||||
|
auto filename = section.data.data() + info.filename;
|
||||||
|
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "version", info.version);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "textSize", info.textSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "textAlign", info.textAlign);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "dataSize", info.dataSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "dataAlign", info.dataAlign);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "loadSize", info.loadSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "loadAlign", info.loadAlign);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "tempSize", info.tempSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "trampAdjust", info.trampAdjust);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "trampAddition", info.trampAddition);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "sdaBase", info.sdaBase);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "sda2Base", info.sda2Base);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "stackSize", info.stackSize);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "heapSize", info.heapSize);
|
||||||
|
|
||||||
|
if (info.filename) {
|
||||||
|
fmt::print(" {:<20} = {}\n", "filename", filename);
|
||||||
|
} else {
|
||||||
|
fmt::print(" {:<20} = 0\n", "filename");
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "flags", info.flags);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "minSdkVersion", info.minVersion);
|
||||||
|
fmt::print(" {:<20} = {}\n", "compressionLevel", info.compressionLevel);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "fileInfoPad", info.fileInfoPad);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "sdkVersion", info.cafeSdkVersion);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "sdkRevision", info.cafeSdkRevision);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "tlsModuleIndex", info.tlsModuleIndex);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "tlsAlignShift", info.tlsAlignShift);
|
||||||
|
fmt::print(" {:<20} = 0x{:X}\n", "runtimeFileInfoSize", info.runtimeFileInfoSize);
|
||||||
|
|
||||||
|
if (info.tagOffset) {
|
||||||
|
const char *tags = section.data.data() + info.tagOffset;
|
||||||
|
fmt::print(" Tags:\n");
|
||||||
|
|
||||||
|
while (*tags) {
|
||||||
|
auto key = tags;
|
||||||
|
tags += strlen(tags) + 1;
|
||||||
|
auto value = tags;
|
||||||
|
tags += strlen(tags) + 1;
|
||||||
|
|
||||||
|
fmt::print(" \"{}\" = \"{}\"\n", key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatRelType(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::R_PPC_NONE:
|
||||||
|
return "NONE";
|
||||||
|
case elf::R_PPC_ADDR32:
|
||||||
|
return "ADDR32";
|
||||||
|
case elf::R_PPC_ADDR16_LO:
|
||||||
|
return "ADDR16_LO";
|
||||||
|
case elf::R_PPC_ADDR16_HI:
|
||||||
|
return "ADDR16_HI";
|
||||||
|
case elf::R_PPC_ADDR16_HA:
|
||||||
|
return "ADDR16_HA";
|
||||||
|
case elf::R_PPC_REL24:
|
||||||
|
return "REL24";
|
||||||
|
case elf::R_PPC_REL14:
|
||||||
|
return "REL14";
|
||||||
|
case elf::R_PPC_DTPMOD32:
|
||||||
|
return "DTPMOD32";
|
||||||
|
case elf::R_PPC_DTPREL32:
|
||||||
|
return "DTPREL32";
|
||||||
|
case elf::R_PPC_EMB_SDA21:
|
||||||
|
return "EMB_SDA21";
|
||||||
|
case elf::R_PPC_EMB_RELSDA:
|
||||||
|
return "EMB_RELSDA";
|
||||||
|
case elf::R_PPC_DIAB_SDA21_LO:
|
||||||
|
return "DIAB_SDA21_LO";
|
||||||
|
case elf::R_PPC_DIAB_SDA21_HI:
|
||||||
|
return "DIAB_SDA21_HI";
|
||||||
|
case elf::R_PPC_DIAB_SDA21_HA:
|
||||||
|
return "DIAB_SDA21_HA";
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_LO:
|
||||||
|
return "DIAB_RELSDA_LO";
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_HI:
|
||||||
|
return "DIAB_RELSDA_HI";
|
||||||
|
case elf::R_PPC_DIAB_RELSDA_HA:
|
||||||
|
return "DIAB_RELSDA_HA";
|
||||||
|
case elf::R_PPC_GHS_REL16_HA:
|
||||||
|
return "GHS_REL16_HA";
|
||||||
|
case elf::R_PPC_GHS_REL16_HI:
|
||||||
|
return "GHS_REL16_HI";
|
||||||
|
case elf::R_PPC_GHS_REL16_LO:
|
||||||
|
return "GHS_REL16_LO";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSymType(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::STT_NOTYPE:
|
||||||
|
return "NOTYPE";
|
||||||
|
case elf::STT_OBJECT:
|
||||||
|
return "OBJECT";
|
||||||
|
case elf::STT_FUNC:
|
||||||
|
return "FUNC";
|
||||||
|
case elf::STT_SECTION:
|
||||||
|
return "SECTION";
|
||||||
|
case elf::STT_FILE:
|
||||||
|
return "FILE";
|
||||||
|
case elf::STT_COMMON:
|
||||||
|
return "COMMON";
|
||||||
|
case elf::STT_TLS:
|
||||||
|
return "TLS";
|
||||||
|
case elf::STT_LOOS:
|
||||||
|
return "LOOS";
|
||||||
|
case elf::STT_HIOS:
|
||||||
|
return "HIOS";
|
||||||
|
case elf::STT_GNU_IFUNC:
|
||||||
|
return "GNU_IFUNC";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSymBinding(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::STB_LOCAL:
|
||||||
|
return "LOCAL";
|
||||||
|
case elf::STB_GLOBAL:
|
||||||
|
return "GLOBAL";
|
||||||
|
case elf::STB_WEAK:
|
||||||
|
return "WEAK";
|
||||||
|
case elf::STB_GNU_UNIQUE:
|
||||||
|
return "UNIQUE";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
formatSymShndx(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case elf::SHN_UNDEF:
|
||||||
|
return "UND";
|
||||||
|
case elf::SHN_ABS:
|
||||||
|
return "ABS";
|
||||||
|
case elf::SHN_COMMON:
|
||||||
|
return "CMN";
|
||||||
|
case elf::SHN_XINDEX:
|
||||||
|
return "UND";
|
||||||
|
default:
|
||||||
|
return fmt::format("{}", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printRela(std::vector<Section> §ions,
|
||||||
|
const char *shStrTab,
|
||||||
|
Section §ion)
|
||||||
|
{
|
||||||
|
fmt::print(
|
||||||
|
" {:<8} {:<8} {:<16} {:<8} {}\n", "Offset", "Info", "Type", "Value", "Name + Addend");
|
||||||
|
|
||||||
|
auto &symSec = sections[section.header.link];
|
||||||
|
auto symbols = reinterpret_cast<elf::Symbol *>(symSec.data.data());
|
||||||
|
auto &symStrTab = sections[symSec.header.link];
|
||||||
|
|
||||||
|
auto relas = reinterpret_cast<elf::Rela *>(section.data.data());
|
||||||
|
auto count = section.data.size() / sizeof(elf::Rela);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
auto &rela = relas[i];
|
||||||
|
|
||||||
|
auto index = rela.info >> 8;
|
||||||
|
auto type = rela.info & 0xff;
|
||||||
|
auto typeName = formatRelType(type);
|
||||||
|
|
||||||
|
auto symbol = symbols[index];
|
||||||
|
auto name = reinterpret_cast<const char*>(symStrTab.data.data()) + symbol.name;
|
||||||
|
|
||||||
|
fmt::print(
|
||||||
|
" {:08X} {:08X} {:<16} {:08X} {} + {:X}\n",
|
||||||
|
rela.offset,
|
||||||
|
rela.info,
|
||||||
|
typeName,
|
||||||
|
symbol.value,
|
||||||
|
name,
|
||||||
|
rela.addend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printSymTab(std::vector<Section> §ions,
|
||||||
|
Section §ion)
|
||||||
|
{
|
||||||
|
auto strTab = reinterpret_cast<const char*>(sections[section.header.link].data.data());
|
||||||
|
|
||||||
|
fmt::print(
|
||||||
|
" {:<4} {:<8} {:<6} {:<8} {:<8} {:<3} {}\n",
|
||||||
|
"Num", "Value", "Size", "Type", "Bind", "Ndx", "Name");
|
||||||
|
|
||||||
|
auto id = 0u;
|
||||||
|
auto symbols = reinterpret_cast<elf::Symbol *>(section.data.data());
|
||||||
|
auto count = section.data.size() / sizeof(elf::Symbol);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
auto &symbol = symbols[i];
|
||||||
|
|
||||||
|
auto name = strTab + symbol.name;
|
||||||
|
auto binding = symbol.info >> 4;
|
||||||
|
auto type = symbol.info & 0xf;
|
||||||
|
auto typeName = formatSymType(type);
|
||||||
|
auto bindingName = formatSymBinding(binding);
|
||||||
|
auto ndx = formatSymShndx(symbol.shndx);
|
||||||
|
|
||||||
|
fmt::print(
|
||||||
|
" {:>4} {:08X} {:>6} {:<8} {:<8} {:>3} {}\n",
|
||||||
|
id, symbol.value, symbol.size, typeName, bindingName, ndx, name);
|
||||||
|
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printRplImports(std::vector<Section> §ions,
|
||||||
|
uint32_t index,
|
||||||
|
Section §ion)
|
||||||
|
{
|
||||||
|
auto import = reinterpret_cast<elf::RplImport *>(section.data.data());
|
||||||
|
fmt::print(" {:<20} = {}\n", "name", import->name);
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "signature", import->signature);
|
||||||
|
fmt::print(" {:<20} = {}\n", "count", import->count);
|
||||||
|
|
||||||
|
if (import->count) {
|
||||||
|
for (auto &symSection : sections) {
|
||||||
|
if (symSection.header.type != elf::SHT_SYMTAB) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto symbols = reinterpret_cast<elf::Symbol *>(symSection.data.data());
|
||||||
|
auto count = symSection.data.size() / sizeof(elf::Symbol);
|
||||||
|
auto strTab = reinterpret_cast<const char*>(sections[symSection.header.link].data.data());
|
||||||
|
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
auto &symbol = symbols[i];
|
||||||
|
auto type = symbol.info & 0xf;
|
||||||
|
|
||||||
|
if (symbol.shndx == index &&
|
||||||
|
(type == elf::STT_FUNC || type == elf::STT_OBJECT)) {
|
||||||
|
fmt::print(" {}\n", strTab + symbol.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printRplCrcs(std::vector<Section> §ions,
|
||||||
|
const char *shStrTab,
|
||||||
|
Section §ion)
|
||||||
|
{
|
||||||
|
auto crcs = reinterpret_cast<elf::RplCrc *>(section.data.data());
|
||||||
|
auto count = section.data.size() / sizeof(elf::RplCrc);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
auto name = shStrTab + sections[i].header.name;
|
||||||
|
fmt::print(" [{:>2}] 0x{:08X} {}\n", i, static_cast<uint32_t>(crcs[i].crc), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printRplExports(Section §ion)
|
||||||
|
{
|
||||||
|
auto exports = reinterpret_cast<elf::RplExport *>(section.data.data());
|
||||||
|
auto strTab = section.data.data();
|
||||||
|
fmt::print(" {:<20} = 0x{:08X}\n", "signature", exports->signature);
|
||||||
|
fmt::print(" {:<20} = {}\n", "count", exports->count);
|
||||||
|
|
||||||
|
for (auto i = 0u; i < exports->count; ++i) {
|
||||||
|
// TLS exports have the high bit set in name for some unknown reason...
|
||||||
|
auto name = strTab + (exports->exports[i].name & 0x7FFFFFFF);
|
||||||
|
auto value = exports->exports[i].value;
|
||||||
|
|
||||||
|
fmt::print(" 0x{:08X} {}\n", static_cast<uint32_t>(value), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readSection(std::ifstream &fh,
|
||||||
|
elf::SectionHeader &header,
|
||||||
|
std::vector<char> &data)
|
||||||
|
{
|
||||||
|
// Read section header
|
||||||
|
fh.read(reinterpret_cast<char*>(&header), sizeof(elf::SectionHeader));
|
||||||
|
|
||||||
|
if (header.type == elf::SHT_NOBITS || !header.size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read section data
|
||||||
|
if (header.flags & elf::SHF_DEFLATED) {
|
||||||
|
auto stream = z_stream {};
|
||||||
|
auto ret = Z_OK;
|
||||||
|
|
||||||
|
// Read the original size
|
||||||
|
uint32_t size = 0;
|
||||||
|
fh.seekg(header.offset.value());
|
||||||
|
fh.read(reinterpret_cast<char *>(&size), sizeof(uint32_t));
|
||||||
|
size = byte_swap(size);
|
||||||
|
data.resize(size);
|
||||||
|
|
||||||
|
// Inflate
|
||||||
|
memset(&stream, 0, sizeof(stream));
|
||||||
|
stream.zalloc = Z_NULL;
|
||||||
|
stream.zfree = Z_NULL;
|
||||||
|
stream.opaque = Z_NULL;
|
||||||
|
|
||||||
|
ret = inflateInit(&stream);
|
||||||
|
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
fmt::print("Couldn't decompress .rpx section because inflateInit returned {}\n", ret);
|
||||||
|
data.clear();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
std::vector<char> temp;
|
||||||
|
temp.resize(header.size-sizeof(uint32_t));
|
||||||
|
fh.read(temp.data(), temp.size());
|
||||||
|
|
||||||
|
stream.avail_in = header.size;
|
||||||
|
stream.next_in = reinterpret_cast<Bytef*>(temp.data());
|
||||||
|
stream.avail_out = static_cast<uInt>(data.size());
|
||||||
|
stream.next_out = reinterpret_cast<Bytef*>(data.data());
|
||||||
|
|
||||||
|
ret = inflate(&stream, Z_FINISH);
|
||||||
|
|
||||||
|
if (ret != Z_OK && ret != Z_STREAM_END) {
|
||||||
|
fmt::print("Couldn't decompress .rpx section because inflate returned {}\n", ret);
|
||||||
|
data.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inflateEnd(&stream);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.resize(header.size);
|
||||||
|
fh.seekg(header.offset.value());
|
||||||
|
fh.read(data.data(), header.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
excmd::parser parser;
|
||||||
|
excmd::option_state options;
|
||||||
|
using excmd::description;
|
||||||
|
using excmd::value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
parser.global_options()
|
||||||
|
.add_option("H,help",
|
||||||
|
description { "Show help." })
|
||||||
|
.add_option("a,all",
|
||||||
|
description { "Equivalent to: -h -S -s -r -i -x -c -f" })
|
||||||
|
.add_option("h,file-header",
|
||||||
|
description { "Display the ELF file header" })
|
||||||
|
.add_option("S,sections",
|
||||||
|
description { "Display the sections' header" })
|
||||||
|
.add_option("s,symbols",
|
||||||
|
description { "Display the symbol table" })
|
||||||
|
.add_option("r,relocs",
|
||||||
|
description { "Display the relocations" })
|
||||||
|
.add_option("i,imports",
|
||||||
|
description { "Display the RPL imports" })
|
||||||
|
.add_option("x,exports",
|
||||||
|
description { "Display the RPL exports" })
|
||||||
|
.add_option("c,crc",
|
||||||
|
description { "Display the RPL crc" })
|
||||||
|
.add_option("f,file-info",
|
||||||
|
description { "Display the RPL file info" });
|
||||||
|
|
||||||
|
parser.default_command()
|
||||||
|
.add_argument("path",
|
||||||
|
description { "Path to RPL file" },
|
||||||
|
value<std::string> {});
|
||||||
|
|
||||||
|
options = parser.parse(argc, argv);
|
||||||
|
} catch (excmd::exception ex) {
|
||||||
|
std::cout << "Error parsing options: " << ex.what() << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.empty() || options.has("help") || !options.has("path")) {
|
||||||
|
fmt::print("{} <options> path\n", argv[0]);
|
||||||
|
fmt::print("{}\n", parser.format_help(argv[0]));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto all = options.has("all");
|
||||||
|
|
||||||
|
auto dumpElfHeader = all || options.has("file-header");
|
||||||
|
auto dumpSectionSummary = all || options.has("sections");
|
||||||
|
auto dumpSectionRela = all || options.has("relocs");
|
||||||
|
auto dumpSectionSymtab = all || options.has("symbols");
|
||||||
|
auto dumpSectionRplExports = all || options.has("exports");
|
||||||
|
auto dumpSectionRplImports = all || options.has("imports");
|
||||||
|
auto dumpSectionRplCrcs = all || options.has("crc");
|
||||||
|
auto dumpSectionRplFileinfo = all || options.has("file-info");
|
||||||
|
auto path = options.get<std::string>("path");
|
||||||
|
|
||||||
|
// If no options are set (other than "path"), let's default to a summary
|
||||||
|
if (options.set_options.size() == 1) {
|
||||||
|
dumpElfHeader = true;
|
||||||
|
dumpSectionSummary = true;
|
||||||
|
dumpSectionRplFileinfo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file
|
||||||
|
std::ifstream fh { path, std::ifstream::binary };
|
||||||
|
|
||||||
|
if (!fh.is_open()) {
|
||||||
|
fmt::print("Could not open {} for reading\n", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
elf::Header header;
|
||||||
|
fh.read(reinterpret_cast<char*>(&header), sizeof(elf::Header));
|
||||||
|
|
||||||
|
if (header.magic != elf::HeaderMagic) {
|
||||||
|
fmt::print("Invalid ELF magic header\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read sections
|
||||||
|
auto sections = std::vector<Section> {};
|
||||||
|
|
||||||
|
for (auto i = 0u; i < header.shnum; ++i) {
|
||||||
|
Section section;
|
||||||
|
fh.seekg(header.shoff + header.shentsize * i);
|
||||||
|
|
||||||
|
if (!readSection(fh, section.header, section.data)) {
|
||||||
|
fmt::print("Error reading section {}", i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.push_back(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find strtab
|
||||||
|
auto shStrTab = reinterpret_cast<const char *>(sections[header.shstrndx].data.data());
|
||||||
|
|
||||||
|
// Format shit
|
||||||
|
if (dumpElfHeader) {
|
||||||
|
printHeader(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dumpSectionSummary) {
|
||||||
|
printSectionSummary(sections, shStrTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print section data
|
||||||
|
for (auto i = 0u; i < sections.size(); ++i) {
|
||||||
|
auto §ion = sections[i];
|
||||||
|
auto name = shStrTab + section.header.name;
|
||||||
|
auto printSectionHeader = [&](){
|
||||||
|
fmt::print(
|
||||||
|
"Section {}: {}, {}, {} bytes\n",
|
||||||
|
i, formatSHT(section.header.type), name, section.data.size());
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (section.header.type) {
|
||||||
|
case elf::SHT_NULL:
|
||||||
|
case elf::SHT_NOBITS:
|
||||||
|
// Print nothing
|
||||||
|
break;
|
||||||
|
case elf::SHT_RELA:
|
||||||
|
if (!dumpSectionRela) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printSectionHeader();
|
||||||
|
printRela(sections, shStrTab, section);
|
||||||
|
break;
|
||||||
|
case elf::SHT_SYMTAB:
|
||||||
|
if (!dumpSectionSymtab) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printSectionHeader();
|
||||||
|
printSymTab(sections, section);
|
||||||
|
break;
|
||||||
|
case elf::SHT_STRTAB:
|
||||||
|
break;
|
||||||
|
case elf::SHT_PROGBITS:
|
||||||
|
break;
|
||||||
|
case elf::SHT_RPL_EXPORTS:
|
||||||
|
if (!dumpSectionRplExports) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printSectionHeader();
|
||||||
|
printRplExports(section);
|
||||||
|
break;
|
||||||
|
case elf::SHT_RPL_IMPORTS:
|
||||||
|
if (!dumpSectionRplImports) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printSectionHeader();
|
||||||
|
printRplImports(sections, i, section);
|
||||||
|
break;
|
||||||
|
case elf::SHT_RPL_CRCS:
|
||||||
|
if (!dumpSectionRplCrcs) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printSectionHeader();
|
||||||
|
printRplCrcs(sections, shStrTab, section);
|
||||||
|
break;
|
||||||
|
case elf::SHT_RPL_FILEINFO:
|
||||||
|
if (!dumpSectionRplFileinfo) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printSectionHeader();
|
||||||
|
printFileInfo(section);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,7 +1,15 @@
|
|||||||
add_executable(wut-rplgen rplgen.cpp)
|
project(rplgen)
|
||||||
target_include_directories(wut-rplgen PRIVATE
|
|
||||||
|
file(GLOB_RECURSE SOURCE_FILES *.cpp)
|
||||||
|
file(GLOB_RECURSE HEADER_FILES *.h)
|
||||||
|
|
||||||
|
add_executable(rplgen
|
||||||
|
${SOURCE_FILES} ${HEADER_FILES})
|
||||||
|
|
||||||
|
target_include_directories(rplgen PRIVATE
|
||||||
${ZLIB_INCLUDE_DIR})
|
${ZLIB_INCLUDE_DIR})
|
||||||
target_link_libraries(wut-rplgen
|
|
||||||
|
target_link_libraries(rplgen
|
||||||
${ZLIB_LIBRARIES})
|
${ZLIB_LIBRARIES})
|
||||||
|
|
||||||
install(TARGETS wut-rplgen RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
install(TARGETS rplgen RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
||||||
|
14
tools/udplogserver/CMakeLists.txt
Normal file
14
tools/udplogserver/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
project(udplogserver)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SOURCE_FILES *.cpp)
|
||||||
|
file(GLOB_RECURSE HEADER_FILES *.h)
|
||||||
|
|
||||||
|
add_executable(udplogserver
|
||||||
|
${SOURCE_FILES}
|
||||||
|
${HEADER_FILES})
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_link_libraries(udplogserver PRIVATE ws2_32)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS udplogserver RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
106
tools/udplogserver/main.cpp
Normal file
106
tools/udplogserver/main.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#ifdef _WIN32
|
||||||
|
#include <WinSock2.h>
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#define SERVER_PORT 4405
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
unsigned short port = SERVER_PORT;
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
port = atoi(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSADATA wsaData;
|
||||||
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) == SOCKET_ERROR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create socket
|
||||||
|
auto fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (fd == INVALID_SOCKET) {
|
||||||
|
WSACleanup();
|
||||||
|
#else
|
||||||
|
if (fd < 0) {
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set non blocking
|
||||||
|
#ifdef _WIN32
|
||||||
|
u_long mode = 1;
|
||||||
|
ioctlsocket(fd, FIONBIO, &mode);
|
||||||
|
#else
|
||||||
|
int flags = fcntl(fd, F_GETFL, 0);
|
||||||
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Bind socket
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
closesocket(fd);
|
||||||
|
WSACleanup();
|
||||||
|
#else
|
||||||
|
close(fd);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive data
|
||||||
|
char buffer[2048];
|
||||||
|
bool running = true;
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
fd_set fdsRead;
|
||||||
|
FD_ZERO(&fdsRead);
|
||||||
|
FD_SET(fd, &fdsRead);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 10000;
|
||||||
|
|
||||||
|
if (select(fd + 1, &fdsRead, NULL, NULL, &tv) == 1) {
|
||||||
|
struct sockaddr_in from;
|
||||||
|
#ifdef _WIN32
|
||||||
|
int fromLen = sizeof(from);
|
||||||
|
#else
|
||||||
|
socklen_t fromLen = sizeof(from);
|
||||||
|
#endif
|
||||||
|
int recvd = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &from, &fromLen);
|
||||||
|
|
||||||
|
if (recvd > 0) {
|
||||||
|
buffer[recvd] = 0;
|
||||||
|
std::cout << buffer;
|
||||||
|
std::cout.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
closesocket(fd);
|
||||||
|
WSACleanup();
|
||||||
|
#else
|
||||||
|
close(fd);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user