diff --git a/build.sh b/build.sh index 8fb5383..eda748a 100755 --- a/build.sh +++ b/build.sh @@ -145,20 +145,23 @@ configure() { meson build/meson64 --libdir lib/mangohud/lib --prefix /usr -Dappend_libdir_mangohud=false -Dld_libdir_prefix=true -Dld_libdir_abs=true $@ ${CONFIGURE_OPTS} fi if [[ ! -f "build/meson32/build.ninja" ]]; then - export CC="gcc -m32" - export CXX="g++ -m32" - export PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}" - export LLVM_CONFIG="/usr/bin/llvm-config32" + + CC="gcc -m32" \ + CFLAGS="-m32" + CXX="g++ -m32" \ + CCCFLAGS="-m32" + PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}" \ + LLVM_CONFIG="/usr/bin/llvm-config32" \ meson build/meson32 --libdir lib/mangohud/lib32 --prefix /usr -Dappend_libdir_mangohud=false -Dld_libdir_prefix=true -Dld_libdir_abs=true $@ ${CONFIGURE_OPTS} fi } build() { - if [[ ! -f "build/meson64/build.ninja" ]]; then + if [[ ! -f "build/meson64/build.ninja" ]] || [[ ! -f "build/meson32/build.ninja" ]]; then configure $@ fi - DESTDIR="$PWD/build/release" ninja -C build/meson32 install - DESTDIR="$PWD/build/release" ninja -C build/meson64 install + DESTDIR="$PWD/build/release" ninja -v -C build/meson64 install + DESTDIR="$PWD/build/release" ninja -v -C build/meson32 install } package() { diff --git a/src/gui/gui.py b/src/gui/gui.py index f75de48..342e932 100755 --- a/src/gui/gui.py +++ b/src/gui/gui.py @@ -20,7 +20,9 @@ msg_in.ParseFromString(data) gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, GLib, Gdk, Gio +from gi.repository import Gtk, GLib, Gdk, Gio, GObject + +GObject.threads_init() screen = Gdk.Screen.get_default() gtk_provider = Gtk.CssProvider() @@ -48,7 +50,8 @@ fps_label = builder.get_object("fps") app_name_label = builder.get_object("app_name") api_label = builder.get_object("api") -SOCKET_NAME = "/tmp/9Lq7BNBnBycd6nxy.socket" +SOCKET_NAME = "/tmp/mangohud_server.socket" +ADDRESS = ("localhost", 9869) import socket @@ -68,26 +71,45 @@ def recv(sock): return msg thread = None +stop = False -def connection_thread(): - global thread - with socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM | socket.SOCK_CLOEXEC) as sock: - sock.connect(SOCKET_NAME) +stop_ev = threading.Event() - while True: - msg = pb.Message(protocol_version=1, client_type=pb.ClientType.GUI) - send(sock, msg) +def thread_loop(sock): + while not stop and not stop_ev.is_set(): + msg = pb.Message(protocol_version=1, client_type=pb.ClientType.GUI) + send(sock, msg) - msg = recv(sock) - print(msg) + msg = recv(sock) + print(msg) - fps = msg.fps - GLib.idle_add(fps_label.set_text, f"{fps:.3f}") - program_name = msg.program_name - GLib.idle_add(app_name_label.set_text, f"{program_name}") - GLib.idle_add(api_label.set_text, f"") + fps = msg.fps + GLib.idle_add(fps_label.set_text, f"{fps:.3f}") + program_name = msg.program_name + GLib.idle_add(app_name_label.set_text, f"{program_name}") + GLib.idle_add(api_label.set_text, f"") - time.sleep(0.05) + time.sleep(0.05) + + +def connection_thread(): + global thread + if True: + addresses = socket.getaddrinfo(ADDRESS[0], ADDRESS[1], proto=socket.IPPROTO_TCP) + assert addresses + address = addresses[0] # (family, type, proto, canonname, sockaddr) + family, type_, proto, canonname, sockaddr = address + assert type_ == socket.SOCK_STREAM + print(f"Connecting to {address}") + with socket.socket(family=family, type=socket.SOCK_STREAM | socket.SOCK_CLOEXEC, proto=proto) as sock: + sock.connect(sockaddr) + thread_loop(sock) + sock.close() + else: + print(f"Connecting to {SOCKET_NAME}") + with socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM | socket.SOCK_CLOEXEC) as sock: + sock.connect(SOCKET_NAME) + thread_loop(sock) sock.close() print("Disconnected") thread = None @@ -100,7 +122,7 @@ def connect(button): print("Connecting...") # button.label.set_text("Connecting...") thread = threading.Thread(target=connection_thread) - thread.daemon = True + # thread.daemon = True # This means to not wait for the thread on exit. Just kill it. thread.start() handlers = { @@ -110,9 +132,13 @@ handlers = { builder.connect_signals(handlers) window = builder.get_object("window_main") -window.show_all() +window.connect("destroy", Gtk.main_quit) + +window.show_all() Gtk.main() +stop = True +stop_ev.set() diff --git a/src/gui/protos/mangohud_pb2.py b/src/gui/protos/mangohud_pb2.py index 9911b2b..1b05380 100644 --- a/src/gui/protos/mangohud_pb2.py +++ b/src/gui/protos/mangohud_pb2.py @@ -20,7 +20,7 @@ DESCRIPTOR = _descriptor.FileDescriptor( syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0emangohud.proto\"\xed\x06\n\x07Message\x12\x18\n\x10protocol_version\x18\x01 \x01(\r\x12 \n\x0b\x63lient_type\x18\x64 \x01(\x0e\x32\x0b.ClientType\x12\x15\n\x05\x61live\x18\x02 \x01(\x0b\x32\x06.Alive\x12#\n\x0c\x61rchitecture\x18\x03 \x01(\x0b\x32\r.Architecture\x12\x14\n\x0cmachine_name\x18\x04 \x01(\t\x12\x0b\n\x03pid\x18\x05 \x01(\x04\x12\x0b\n\x03uid\x18\x06 \x01(\x04\x12\x10\n\x08username\x18\x07 \x01(\t\x12\x14\n\x0cprogram_name\x18\x08 \x01(\t\x12 \n\x0brender_info\x18\t \x01(\x0b\x32\x0b.RenderInfo\x12!\n\tblacklist\x18\n \x01(\x0b\x32\x0e.BlackListInfo\x12&\n\x0e\x63onfig_request\x18\x0b \x01(\x0b\x32\x0e.ConfigRequest\x12\x1c\n\x0b\x63onfig_data\x18\x0c \x01(\x0b\x32\x07.Config\x12$\n\rconfig_reload\x18\r \x01(\x0b\x32\r.ConfigReload\x12\x1d\n\ttimestamp\x18\x14 \x01(\x0b\x32\n.Timestamp\x12\x17\n\x0f\x61pp_uptime_msec\x18\x15 \x01(\x04\x12\x0b\n\x03\x66ps\x18\x1e \x01(\x02\x12\x1e\n\nframetimes\x18\x1f \x03(\x0b\x32\n.FrameTime\x12\x19\n\x11stream_frametimes\x18( \x01(\x08\x12\x10\n\x08show_hud\x18) \x01(\x08\x12\x14\n\x0c\x66rame_limits\x18* \x03(\x02\x12\r\n\x05vsync\x18+ \x01(\x08\x12\x1b\n\x13media_player_string\x18\x32 \x01(\t\x12\x15\n\rextra_string1\x18\x33 \x01(\t\x12\x15\n\rextra_string2\x18\x34 \x01(\t\x12\x1a\n\x08gpu_info\x18< \x03(\x0b\x32\x08.GpuInfo\x12\x1a\n\x08\x63pu_info\x18= \x01(\x0b\x32\x08.CpuInfo\x12\"\n\x10\x63pu_info_details\x18> \x01(\x0b\x32\x08.CpuInfo\x12\x1a\n\x08mem_info\x18? \x01(\x0b\x32\x08.MemInfo\x12!\n\x0c\x61pp_gpu_info\x18\x46 \x03(\x0b\x32\x0b.GpuInfoApp\x12!\n\x0c\x61pp_cpu_info\x18G \x01(\x0b\x32\x0b.CpuInfoApp\x12!\n\x0c\x61pp_mem_info\x18I \x01(\x0b\x32\x0b.MemInfoApp\"\x16\n\x05\x41live\x12\r\n\x05\x64ummy\x18\x01 \x01(\r\"\xa8\x01\n\x0c\x41rchitecture\x12\n\n\x02os\x18\x01 \x01(\t\x12\x16\n\x0ekernel_version\x18\x02 \x01(\t\x12\x14\n\x0c\x61rchitecture\x18\x03 \x01(\t\x12 \n\x18mangohud_library_version\x18\x04 \x01(\t\x12\x1e\n\x16mangohud_server_verion\x18\x05 \x01(\t\x12\x1c\n\x14mangohud_gui_version\x18\x06 \x01(\t\"\x91\x01\n\nRenderInfo\x12\x0e\n\x06opengl\x18\x01 \x01(\x08\x12\x0e\n\x06vulkan\x18\x02 \x01(\x08\x12\x16\n\x0eopengl_version\x18\n \x01(\t\x12\x1a\n\x12opengl_device_name\x18\x0b \x01(\t\x12\x1a\n\x12vulkan_driver_name\x18\x14 \x01(\t\x12\x13\n\x0b\x65ngine_name\x18\x15 \x01(\t\"=\n\rBlackListInfo\x12\x13\n\x0b\x62lacklisted\x18\x01 \x01(\x08\x12\x17\n\x0f\x62lacklist_names\x18\x02 \x03(\t\"I\n\rConfigRequest\x12\x14\n\x0cmachine_name\x18\x01 \x01(\t\x12\x14\n\x0cprogram_name\x18\x02 \x01(\t\x12\x0c\n\x04wine\x18\x03 \x01(\x08\"#\n\x0c\x43onfigReload\x12\x13\n\x0b\x63onfig_path\x18\x01 \x01(\t\"\xc3\x03\n\x06\x43onfig\x12\"\n\x1a\x66ps_sampling_interval_msec\x18\x01 \x01(\r\x12\x10\n\x08show_hud\x18\x02 \x01(\x08\x12)\n\x0chud_geometry\x18\x03 \x01(\x0b\x32\x13.Config.HudGeometry\x12!\n\x08\x65lements\x18\x04 \x03(\x0b\x32\x0f.Config.Element\x12#\n\x0etoggle_logging\x18\x05 \x01(\x0b\x32\x0b.Config.Key\x12\x1f\n\ntoggle_hud\x18\x06 \x01(\x0b\x32\x0b.Config.Key\x12\x1f\n\nreload_cfg\x18\x07 \x01(\x0b\x32\x0b.Config.Key\x1aP\n\x0bHudGeometry\x12\r\n\x05width\x18\x01 \x01(\r\x12\x0e\n\x06height\x18\x02 \x01(\r\x12\x10\n\x08offset_x\x18\x03 \x01(\r\x12\x10\n\x08offset_y\x18\x04 \x01(\r\x1a\x61\n\x07\x45lement\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ont\x18\x02 \x01(\t\x12\r\n\x05\x63olor\x18\x03 \x01(\t\x12\x0c\n\x04text\x18\x04 \x01(\t\x12\r\n\x05value\x18\x05 \x01(\t\x12\x0e\n\x06suffix\x18\x06 \x01(\t\x1a\x19\n\x03Key\x12\x12\n\nkeybinding\x18\x01 \x01(\t\"4\n\tTimestamp\x12\x14\n\x0c\x63lock_source\x18\x01 \x01(\t\x12\x11\n\ttimestamp\x18\x02 \x01(\x04\";\n\tFrameTime\x12\x11\n\ttimestamp\x18\x01 \x01(\x04\x12\r\n\x05index\x18\x02 \x01(\x04\x12\x0c\n\x04time\x18\x03 \x01(\r\"\xa1\x04\n\x07GpuInfo\x12\x0b\n\x03\x62us\x18\x01 \x01(\x05\x12\x14\n\x0cpci_dev_info\x18\x02 \x01(\t\x12\x10\n\x08gpu_name\x18\x03 \x01(\t\x12\x13\n\x0b\x63ore_temp_C\x18\n \x01(\x05\x12\x12\n\nmem_temp_C\x18\x0b \x01(\x05\x12\x15\n\rfan_speed_RPM\x18\x0c \x01(\x05\x12\x16\n\x0e\x63ore_clock_kHz\x18\x14 \x01(\x05\x12\x1a\n\x12\x63ore_clock_kHz_max\x18\x15 \x01(\x05\x12\x15\n\rmem_clock_kHz\x18\x16 \x01(\x05\x12\x19\n\x11mem_clock_max_kHz\x18\x17 \x01(\x05\x12\x10\n\x08gpu_load\x18\x1e \x01(\x02\x12\x0f\n\x07power_W\x18\x1f \x01(\x02\x12\x14\n\x0c\x65vent_engine\x18\x33 \x01(\x02\x12\x12\n\ntesselator\x18\x34 \x01(\x02\x12\x19\n\x11texture_addresser\x18\x35 \x01(\x02\x12\x15\n\rshader_export\x18\x36 \x01(\x02\x12#\n\x1bsequencer_instruction_cache\x18\x37 \x01(\x02\x12\x1b\n\x13shader_interpolator\x18\x38 \x01(\x02\x12\x16\n\x0escan_converter\x18\x39 \x01(\x02\x12\x1a\n\x12primitive_assembly\x18: \x01(\x02\x12\x13\n\x0b\x64\x65pth_block\x18; \x01(\x02\x12\x13\n\x0b\x63olor_block\x18< \x01(\x02\x12\x0b\n\x03gtt\x18= \x01(\x04\x12\x0f\n\x07gtt_max\x18> \x01(\x04\"\xf8\x02\n\x07\x43puInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x16\n\x0eisa_extensions\x18\x02 \x03(\t\x12\x18\n\x10\x63pufreq_governor\x18\x03 \x01(\t\x12\x16\n\x0e\x63ore_clock_kHz\x18\x04 \x03(\x05\x12\x13\n\x0b\x63ore_temp_C\x18\x05 \x03(\x05\x12\x0c\n\x04load\x18\x06 \x03(\x02\x12\x11\n\tload_user\x18\x07 \x01(\x02\x12\x10\n\x08load_sys\x18\x08 \x01(\x02\x12\x11\n\tload_nice\x18\t \x01(\x02\x12\x11\n\tload_idle\x18\n \x01(\x02\x12\x11\n\tload_wait\x18\x0b \x01(\x02\x12\r\n\x05tasks\x18\x14 \x01(\r\x12\x16\n\x0etasks_runnable\x18\x15 \x01(\r\x12\x15\n\rtasks_running\x18\x16 \x01(\r\x12\x15\n\rtasks_stopped\x18\x17 \x01(\r\x12\x14\n\x0ctasks_zombie\x18\x18 \x01(\r\x12\x13\n\x0buptime_msec\x18\x1e \x01(\x04\x12\x14\n\x0cload_average\x18( \x03(\x02\"\xa1\x01\n\x07MemInfo\x12\r\n\x05total\x18\x01 \x01(\x04\x12\x0c\n\x04\x66ree\x18\x02 \x01(\x04\x12\x0c\n\x04used\x18\x03 \x01(\x04\x12\x0f\n\x07\x62uffers\x18\x04 \x01(\x04\x12\r\n\x05\x63\x61\x63he\x18\x05 \x01(\x04\x12\x11\n\tavailable\x18\x06 \x01(\x04\x12\x12\n\nswap_total\x18\n \x01(\x04\x12\x11\n\tswap_free\x18\x0b \x01(\x04\x12\x11\n\tswap_used\x18\x0c \x01(\x04\"2\n\nGpuInfoApp\x12\x11\n\tvram_used\x18\x01 \x01(\x04\x12\x11\n\tpipelines\x18\x02 \x01(\x04\"_\n\nCpuInfoApp\x12\x1c\n\x14\x63pu_usage_total_usec\x18\x01 \x01(\x04\x12\x1d\n\x15wall_clock_total_usec\x18\x02 \x01(\x04\x12\x14\n\x0cthread_count\x18\x03 \x01(\r\"\x99\x01\n\nMemInfoApp\x12\x0b\n\x03rss\x18\x01 \x01(\x04\x12\x0c\n\x04text\x18\x02 \x01(\x04\x12\x0c\n\x04swap\x18\x03 \x01(\x04\x12\x0c\n\x04\x63ode\x18\x04 \x01(\x04\x12\x0e\n\x06\x63\x61\x63hed\x18\x05 \x01(\x04\x12\x0e\n\x06locked\x18\x06 \x01(\x04\x12\x0e\n\x06sahred\x18\x07 \x01(\x04\x12\x11\n\tmaj_fault\x18\n \x01(\x04\x12\x11\n\tmin_fault\x18\x0b \x01(\x04**\n\nClientType\x12\x07\n\x03\x41PP\x10\x00\x12\n\n\x06SERVER\x10\x01\x12\x07\n\x03GUI\x10\x02\x62\x06proto3' + serialized_pb=b'\n\x0emangohud.proto\"\x89\x07\n\x07Message\x12\x18\n\x10protocol_version\x18\x01 \x01(\r\x12 \n\x0b\x63lient_type\x18\x64 \x01(\x0e\x32\x0b.ClientType\x12\x15\n\x05\x61live\x18\x02 \x01(\x0b\x32\x06.Alive\x12#\n\x0c\x61rchitecture\x18\x03 \x01(\x0b\x32\r.Architecture\x12\x14\n\x0cmachine_name\x18\x04 \x01(\t\x12\x0b\n\x03pid\x18\x05 \x01(\x04\x12\x0b\n\x03uid\x18\x06 \x01(\x04\x12\x10\n\x08username\x18\x07 \x01(\t\x12\x14\n\x0cprogram_name\x18\x08 \x01(\t\x12 \n\x0brender_info\x18\t \x01(\x0b\x32\x0b.RenderInfo\x12!\n\tblacklist\x18\n \x01(\x0b\x32\x0e.BlackListInfo\x12&\n\x0e\x63onfig_request\x18\x0b \x01(\x0b\x32\x0e.ConfigRequest\x12\x1c\n\x0b\x63onfig_data\x18\x0c \x01(\x0b\x32\x07.Config\x12$\n\rconfig_reload\x18\r \x01(\x0b\x32\r.ConfigReload\x12\x1d\n\ttimestamp\x18\x14 \x01(\x0b\x32\n.Timestamp\x12\x17\n\x0f\x61pp_uptime_msec\x18\x15 \x01(\x04\x12\x0b\n\x03\x66ps\x18\x1e \x01(\x02\x12\x1e\n\nframetimes\x18\x1f \x03(\x0b\x32\n.FrameTime\x12\x19\n\x11stream_frametimes\x18( \x01(\x08\x12\x10\n\x08show_hud\x18) \x01(\x08\x12\x14\n\x0c\x66rame_limits\x18* \x03(\x02\x12\r\n\x05vsync\x18+ \x01(\x08\x12\x1b\n\x13media_player_string\x18\x32 \x01(\t\x12\x15\n\rextra_string1\x18\x33 \x01(\t\x12\x15\n\rextra_string2\x18\x34 \x01(\t\x12\x1a\n\x08gpu_info\x18< \x03(\x0b\x32\x08.GpuInfo\x12\x1a\n\x08\x63pu_info\x18= \x01(\x0b\x32\x08.CpuInfo\x12\"\n\x10\x63pu_info_details\x18> \x01(\x0b\x32\x08.CpuInfo\x12\x1a\n\x08mem_info\x18? \x01(\x0b\x32\x08.MemInfo\x12!\n\x0c\x61pp_gpu_info\x18\x46 \x03(\x0b\x32\x0b.GpuInfoApp\x12!\n\x0c\x61pp_cpu_info\x18G \x01(\x0b\x32\x0b.CpuInfoApp\x12!\n\x0c\x61pp_mem_info\x18I \x01(\x0b\x32\x0b.MemInfoApp\x12\x1a\n\x07\x63lients\x18\xc8\x01 \x03(\x0b\x32\x08.Message\"\x16\n\x05\x41live\x12\r\n\x05\x64ummy\x18\x01 \x01(\r\"\xa8\x01\n\x0c\x41rchitecture\x12\n\n\x02os\x18\x01 \x01(\t\x12\x16\n\x0ekernel_version\x18\x02 \x01(\t\x12\x14\n\x0c\x61rchitecture\x18\x03 \x01(\t\x12 \n\x18mangohud_library_version\x18\x04 \x01(\t\x12\x1e\n\x16mangohud_server_verion\x18\x05 \x01(\t\x12\x1c\n\x14mangohud_gui_version\x18\x06 \x01(\t\"\x91\x01\n\nRenderInfo\x12\x0e\n\x06opengl\x18\x01 \x01(\x08\x12\x0e\n\x06vulkan\x18\x02 \x01(\x08\x12\x16\n\x0eopengl_version\x18\n \x01(\t\x12\x1a\n\x12opengl_device_name\x18\x0b \x01(\t\x12\x1a\n\x12vulkan_driver_name\x18\x14 \x01(\t\x12\x13\n\x0b\x65ngine_name\x18\x15 \x01(\t\"=\n\rBlackListInfo\x12\x13\n\x0b\x62lacklisted\x18\x01 \x01(\x08\x12\x17\n\x0f\x62lacklist_names\x18\x02 \x03(\t\"I\n\rConfigRequest\x12\x14\n\x0cmachine_name\x18\x01 \x01(\t\x12\x14\n\x0cprogram_name\x18\x02 \x01(\t\x12\x0c\n\x04wine\x18\x03 \x01(\x08\"#\n\x0c\x43onfigReload\x12\x13\n\x0b\x63onfig_path\x18\x01 \x01(\t\"\xc3\x03\n\x06\x43onfig\x12\"\n\x1a\x66ps_sampling_interval_msec\x18\x01 \x01(\r\x12\x10\n\x08show_hud\x18\x02 \x01(\x08\x12)\n\x0chud_geometry\x18\x03 \x01(\x0b\x32\x13.Config.HudGeometry\x12!\n\x08\x65lements\x18\x04 \x03(\x0b\x32\x0f.Config.Element\x12#\n\x0etoggle_logging\x18\x05 \x01(\x0b\x32\x0b.Config.Key\x12\x1f\n\ntoggle_hud\x18\x06 \x01(\x0b\x32\x0b.Config.Key\x12\x1f\n\nreload_cfg\x18\x07 \x01(\x0b\x32\x0b.Config.Key\x1aP\n\x0bHudGeometry\x12\r\n\x05width\x18\x01 \x01(\r\x12\x0e\n\x06height\x18\x02 \x01(\r\x12\x10\n\x08offset_x\x18\x03 \x01(\r\x12\x10\n\x08offset_y\x18\x04 \x01(\r\x1a\x61\n\x07\x45lement\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ont\x18\x02 \x01(\t\x12\r\n\x05\x63olor\x18\x03 \x01(\t\x12\x0c\n\x04text\x18\x04 \x01(\t\x12\r\n\x05value\x18\x05 \x01(\t\x12\x0e\n\x06suffix\x18\x06 \x01(\t\x1a\x19\n\x03Key\x12\x12\n\nkeybinding\x18\x01 \x01(\t\"4\n\tTimestamp\x12\x14\n\x0c\x63lock_source\x18\x01 \x01(\t\x12\x11\n\ttimestamp\x18\x02 \x01(\x04\";\n\tFrameTime\x12\x11\n\ttimestamp\x18\x01 \x01(\x04\x12\r\n\x05index\x18\x02 \x01(\x04\x12\x0c\n\x04time\x18\x03 \x01(\r\"\xa1\x04\n\x07GpuInfo\x12\x0b\n\x03\x62us\x18\x01 \x01(\x05\x12\x14\n\x0cpci_dev_info\x18\x02 \x01(\t\x12\x10\n\x08gpu_name\x18\x03 \x01(\t\x12\x13\n\x0b\x63ore_temp_C\x18\n \x01(\x05\x12\x12\n\nmem_temp_C\x18\x0b \x01(\x05\x12\x15\n\rfan_speed_RPM\x18\x0c \x01(\x05\x12\x16\n\x0e\x63ore_clock_kHz\x18\x14 \x01(\x05\x12\x1a\n\x12\x63ore_clock_kHz_max\x18\x15 \x01(\x05\x12\x15\n\rmem_clock_kHz\x18\x16 \x01(\x05\x12\x19\n\x11mem_clock_max_kHz\x18\x17 \x01(\x05\x12\x10\n\x08gpu_load\x18\x1e \x01(\x02\x12\x0f\n\x07power_W\x18\x1f \x01(\x02\x12\x14\n\x0c\x65vent_engine\x18\x33 \x01(\x02\x12\x12\n\ntesselator\x18\x34 \x01(\x02\x12\x19\n\x11texture_addresser\x18\x35 \x01(\x02\x12\x15\n\rshader_export\x18\x36 \x01(\x02\x12#\n\x1bsequencer_instruction_cache\x18\x37 \x01(\x02\x12\x1b\n\x13shader_interpolator\x18\x38 \x01(\x02\x12\x16\n\x0escan_converter\x18\x39 \x01(\x02\x12\x1a\n\x12primitive_assembly\x18: \x01(\x02\x12\x13\n\x0b\x64\x65pth_block\x18; \x01(\x02\x12\x13\n\x0b\x63olor_block\x18< \x01(\x02\x12\x0b\n\x03gtt\x18= \x01(\x04\x12\x0f\n\x07gtt_max\x18> \x01(\x04\"\xf8\x02\n\x07\x43puInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x16\n\x0eisa_extensions\x18\x02 \x03(\t\x12\x18\n\x10\x63pufreq_governor\x18\x03 \x01(\t\x12\x16\n\x0e\x63ore_clock_kHz\x18\x04 \x03(\x05\x12\x13\n\x0b\x63ore_temp_C\x18\x05 \x03(\x05\x12\x0c\n\x04load\x18\x06 \x03(\x02\x12\x11\n\tload_user\x18\x07 \x01(\x02\x12\x10\n\x08load_sys\x18\x08 \x01(\x02\x12\x11\n\tload_nice\x18\t \x01(\x02\x12\x11\n\tload_idle\x18\n \x01(\x02\x12\x11\n\tload_wait\x18\x0b \x01(\x02\x12\r\n\x05tasks\x18\x14 \x01(\r\x12\x16\n\x0etasks_runnable\x18\x15 \x01(\r\x12\x15\n\rtasks_running\x18\x16 \x01(\r\x12\x15\n\rtasks_stopped\x18\x17 \x01(\r\x12\x14\n\x0ctasks_zombie\x18\x18 \x01(\r\x12\x13\n\x0buptime_msec\x18\x1e \x01(\x04\x12\x14\n\x0cload_average\x18( \x03(\x02\"\xa1\x01\n\x07MemInfo\x12\r\n\x05total\x18\x01 \x01(\x04\x12\x0c\n\x04\x66ree\x18\x02 \x01(\x04\x12\x0c\n\x04used\x18\x03 \x01(\x04\x12\x0f\n\x07\x62uffers\x18\x04 \x01(\x04\x12\r\n\x05\x63\x61\x63he\x18\x05 \x01(\x04\x12\x11\n\tavailable\x18\x06 \x01(\x04\x12\x12\n\nswap_total\x18\n \x01(\x04\x12\x11\n\tswap_free\x18\x0b \x01(\x04\x12\x11\n\tswap_used\x18\x0c \x01(\x04\"2\n\nGpuInfoApp\x12\x11\n\tvram_used\x18\x01 \x01(\x04\x12\x11\n\tpipelines\x18\x02 \x01(\x04\"_\n\nCpuInfoApp\x12\x1c\n\x14\x63pu_usage_total_usec\x18\x01 \x01(\x04\x12\x1d\n\x15wall_clock_total_usec\x18\x02 \x01(\x04\x12\x14\n\x0cthread_count\x18\x03 \x01(\r\"\x99\x01\n\nMemInfoApp\x12\x0b\n\x03rss\x18\x01 \x01(\x04\x12\x0c\n\x04text\x18\x02 \x01(\x04\x12\x0c\n\x04swap\x18\x03 \x01(\x04\x12\x0c\n\x04\x63ode\x18\x04 \x01(\x04\x12\x0e\n\x06\x63\x61\x63hed\x18\x05 \x01(\x04\x12\x0e\n\x06locked\x18\x06 \x01(\x04\x12\x0e\n\x06sahred\x18\x07 \x01(\x04\x12\x11\n\tmaj_fault\x18\n \x01(\x04\x12\x11\n\tmin_fault\x18\x0b \x01(\x04**\n\nClientType\x12\x07\n\x03\x41PP\x10\x00\x12\n\n\x06SERVER\x10\x01\x12\x07\n\x03GUI\x10\x02\x62\x06proto3' ) _CLIENTTYPE = _descriptor.EnumDescriptor( @@ -48,8 +48,8 @@ _CLIENTTYPE = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=3381, - serialized_end=3423, + serialized_start=3409, + serialized_end=3451, ) _sym_db.RegisterEnumDescriptor(_CLIENTTYPE) @@ -292,6 +292,13 @@ _MESSAGE = _descriptor.Descriptor( message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='clients', full_name='Message.clients', index=32, + number=200, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -305,7 +312,7 @@ _MESSAGE = _descriptor.Descriptor( oneofs=[ ], serialized_start=19, - serialized_end=896, + serialized_end=924, ) @@ -336,8 +343,8 @@ _ALIVE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=898, - serialized_end=920, + serialized_start=926, + serialized_end=948, ) @@ -403,8 +410,8 @@ _ARCHITECTURE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=923, - serialized_end=1091, + serialized_start=951, + serialized_end=1119, ) @@ -470,8 +477,8 @@ _RENDERINFO = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1094, - serialized_end=1239, + serialized_start=1122, + serialized_end=1267, ) @@ -509,8 +516,8 @@ _BLACKLISTINFO = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1241, - serialized_end=1302, + serialized_start=1269, + serialized_end=1330, ) @@ -555,8 +562,8 @@ _CONFIGREQUEST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1304, - serialized_end=1377, + serialized_start=1332, + serialized_end=1405, ) @@ -587,8 +594,8 @@ _CONFIGRELOAD = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1379, - serialized_end=1414, + serialized_start=1407, + serialized_end=1442, ) @@ -640,8 +647,8 @@ _CONFIG_HUDGEOMETRY = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1662, - serialized_end=1742, + serialized_start=1690, + serialized_end=1770, ) _CONFIG_ELEMENT = _descriptor.Descriptor( @@ -706,8 +713,8 @@ _CONFIG_ELEMENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1744, - serialized_end=1841, + serialized_start=1772, + serialized_end=1869, ) _CONFIG_KEY = _descriptor.Descriptor( @@ -737,8 +744,8 @@ _CONFIG_KEY = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1843, - serialized_end=1868, + serialized_start=1871, + serialized_end=1896, ) _CONFIG = _descriptor.Descriptor( @@ -810,8 +817,8 @@ _CONFIG = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1417, - serialized_end=1868, + serialized_start=1445, + serialized_end=1896, ) @@ -849,8 +856,8 @@ _TIMESTAMP = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1870, - serialized_end=1922, + serialized_start=1898, + serialized_end=1950, ) @@ -895,8 +902,8 @@ _FRAMETIME = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1924, - serialized_end=1983, + serialized_start=1952, + serialized_end=2011, ) @@ -1088,8 +1095,8 @@ _GPUINFO = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1986, - serialized_end=2531, + serialized_start=2014, + serialized_end=2559, ) @@ -1239,8 +1246,8 @@ _CPUINFO = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2534, - serialized_end=2910, + serialized_start=2562, + serialized_end=2938, ) @@ -1327,8 +1334,8 @@ _MEMINFO = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2913, - serialized_end=3074, + serialized_start=2941, + serialized_end=3102, ) @@ -1366,8 +1373,8 @@ _GPUINFOAPP = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3076, - serialized_end=3126, + serialized_start=3104, + serialized_end=3154, ) @@ -1412,8 +1419,8 @@ _CPUINFOAPP = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3128, - serialized_end=3223, + serialized_start=3156, + serialized_end=3251, ) @@ -1500,8 +1507,8 @@ _MEMINFOAPP = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3226, - serialized_end=3379, + serialized_start=3254, + serialized_end=3407, ) _MESSAGE.fields_by_name['client_type'].enum_type = _CLIENTTYPE @@ -1521,6 +1528,7 @@ _MESSAGE.fields_by_name['mem_info'].message_type = _MEMINFO _MESSAGE.fields_by_name['app_gpu_info'].message_type = _GPUINFOAPP _MESSAGE.fields_by_name['app_cpu_info'].message_type = _CPUINFOAPP _MESSAGE.fields_by_name['app_mem_info'].message_type = _MEMINFOAPP +_MESSAGE.fields_by_name['clients'].message_type = _MESSAGE _CONFIG_HUDGEOMETRY.containing_type = _CONFIG _CONFIG_ELEMENT.containing_type = _CONFIG _CONFIG_KEY.containing_type = _CONFIG diff --git a/src/meson.build b/src/meson.build index d6eec7c..41e6c20 100644 --- a/src/meson.build +++ b/src/meson.build @@ -59,6 +59,7 @@ if ['windows', 'mingw'].contains(host_machine.system()) ) endif + if is_unixy vklayer_files += files( 'cpu.cpp', @@ -69,8 +70,6 @@ if is_unixy 'elfhacks.cpp', 'real_dlsym.cpp', 'pci_ids.cpp', - 'server/common.c', - 'server/mangohud.pb.c', ) opengl_files = files( @@ -142,6 +141,8 @@ if is_unixy endif endif +subdir('server') + link_args = cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro', '-Wl,--exclude-libs,ALL']) # meson fails to check version-script so just force add link_args += '-Wl,--version-script,@0@'.format(join_paths(meson.current_source_dir(), 'mangohud.version')) @@ -173,8 +174,9 @@ vklayer_mesa_overlay = shared_library( dep_pthread, dep_vulkan, windows_deps], - include_directories : [inc_common], - link_args : link_args + ['-lprotobuf-nanopb'], + include_directories : [inc_common, 'server'], + link_with : [rpc_common], + link_args : link_args, install_dir : libdir_mangohud, install : true ) diff --git a/src/server/build.sh b/src/server/build.sh index 9a38337..2755d1e 100755 --- a/src/server/build.sh +++ b/src/server/build.sh @@ -6,7 +6,19 @@ set -x nanopb_generator.py -s type:FT_POINTER mangohud.proto protoc --python_out=../gui/protos mangohud.proto +#protoc --nanopb_out=./ mangohud.proto +# Instead of -lprotobuf-nanopb +# try these: +# -L/usr/local/lib -lprotobuf-nanopb +# -L/usr/local/lib64 -lprotobuf-nanopb +# /usr/local/lib/libprotobuf-nanopb.a +# /usr/local/lib64/libprotobuf-nanopb.a +# /usr/local/lib32/libprotobuf-nanopb.a +# +# You will need to specifiy proper versions for 64-bit and 32-bit build. +# +# On Debian and Ubuntu, you can just use `-lprotobuf-nanopb`, gcc will find it on its own from standard locations. # We compile both 64-bit and 32-bit versions, to detect for example incorrect # use of fprintf string formats (i.e. %ld instead of using %zu for size_t). @@ -18,4 +30,3 @@ g++ -Wall -g -O2 -o client-demo client_demo.cpp common.c mangohud.pb.c -lprotobu g++ -m32 -Wall -g -O2 -o client-demo_32 client_demo.cpp common.c mangohud.pb.c -lprotobuf-nanopb ldd client-demo | grep -E 'libgcc_s\.so|libstdc\+\+\.so' && echo "Warning: Linked to C++ runtime" - diff --git a/src/server/common.c b/src/server/common.c index 76bccf6..b004baf 100644 --- a/src/server/common.c +++ b/src/server/common.c @@ -33,7 +33,7 @@ #define NOTNULL __attribute__ ((nonnull)) #define NOTHROW __attribute__ ((nothrow)) -// TODO(baryluk_: Set __attribute((visibility("hidden")) on some? +// TODO(baryluk): Set __attribute((visibility("hidden")) on some? // static int set_nonblocking(int fd) { @@ -64,9 +64,14 @@ int client_connect(struct ClientState* client_state) { if (client_state->fd == 0) { // Create local socket. //int data_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); +retry_socket: data_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); // | SOCK_NONBLOCK, 0); // Note: For TCP sockets (AF_INET, AF_INET6 + SOCK_STREAM) we might want SOCK_KEEPALIVE. if (data_socket == -1) { + if (errno == EINTR) { + goto retry_socket; + } + perror("socket"); return errno; // socket } @@ -94,11 +99,17 @@ int client_connect(struct ClientState* client_state) { assert(strlen(SOCKET_NAME) < sizeof(addr.sun_path)); strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); +retry_connect: if (connect(data_socket, (const struct sockaddr *)&addr, sizeof(addr)) != 0) { - perror("connect"); - DEBUG(fprintf(stderr, "The server is down?\n")); - goto error_2; + if (errno != EINPROGRESS) { + if (errno == EINTR) { + goto retry_connect; + } + perror("connect"); + DEBUG(fprintf(stderr, "The server is down?\n")); + goto error_2; + } } if (set_nonblocking(data_socket)) { diff --git a/src/server/common.h b/src/server/common.h index 3612952..979db47 100644 --- a/src/server/common.h +++ b/src/server/common.h @@ -56,7 +56,9 @@ extern "C" { // Note: On Linux, the length must be less than 108 bytes // (including a NULL terminator). // Some implementations have it as short as 92 bytes. -#define SOCKET_NAME "/tmp/9Lq7BNBnBycd6nxy.socket" +// +// TODO(baryluk): Use dynamic name with uid / user. +#define SOCKET_NAME "/tmp/mangohud_server.socket" #define MUST_USE_RESULT __attribute__ ((warn_unused_result)) #define COLD __attribute__ ((cold)) diff --git a/src/server/gen-pb.py b/src/server/gen-pb.py new file mode 100755 index 0000000..3dc68c0 --- /dev/null +++ b/src/server/gen-pb.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +import sys +from subprocess import call +from os.path import dirname +from os import makedirs + +protoc_path = sys.argv[1] +gen_path = sys.argv[2] +proto_file = sys.argv[3] +options_file = sys.argv[4] +build_dir = sys.argv[5] + +source_dir = dirname(proto_file) + +makedirs(build_dir, exist_ok=True) + +cmdline = [protoc_path, '--plugin=protoc-gen-nanopb=' + gen_path, + '-I' + source_dir, + '--nanopb_out=' + '-f ' + options_file + ':' + build_dir, + proto_file] + +sys.stderr.write(" ".join(cmdline) + "\n") +exit(call(cmdline)) diff --git a/src/server/mangohud.options b/src/server/mangohud.options new file mode 100644 index 0000000..e69de29 diff --git a/src/server/mangohud.pb.h b/src/server/mangohud.pb.h index 560197d..31bfb42 100644 --- a/src/server/mangohud.pb.h +++ b/src/server/mangohud.pb.h @@ -208,6 +208,8 @@ typedef struct _Message { struct _CpuInfoApp *app_cpu_info; struct _MemInfoApp *app_mem_info; ClientType *client_type; + pb_size_t clients_count; + struct _Message *clients; } Message; typedef struct _RenderInfo { @@ -236,7 +238,7 @@ extern "C" { #endif /* Initializer values for message structs */ -#define Message_init_default {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL} +#define Message_init_default {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL} #define Alive_init_default {NULL} #define Architecture_init_default {NULL, NULL, NULL, NULL, NULL, NULL} #define RenderInfo_init_default {NULL, NULL, NULL, NULL, NULL, NULL} @@ -255,7 +257,7 @@ extern "C" { #define GpuInfoApp_init_default {NULL, NULL} #define CpuInfoApp_init_default {NULL, NULL, NULL} #define MemInfoApp_init_default {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} -#define Message_init_zero {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL} +#define Message_init_zero {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL} #define Alive_init_zero {NULL} #define Architecture_init_zero {NULL, NULL, NULL, NULL, NULL, NULL} #define RenderInfo_init_zero {NULL, NULL, NULL, NULL, NULL, NULL} @@ -407,6 +409,7 @@ extern "C" { #define Message_app_cpu_info_tag 71 #define Message_app_mem_info_tag 73 #define Message_client_type_tag 100 +#define Message_clients_tag 200 #define RenderInfo_opengl_tag 1 #define RenderInfo_vulkan_tag 2 #define RenderInfo_opengl_version_tag 10 @@ -449,7 +452,8 @@ X(a, POINTER, OPTIONAL, MESSAGE, mem_info, 63) \ X(a, POINTER, REPEATED, MESSAGE, app_gpu_info, 70) \ X(a, POINTER, OPTIONAL, MESSAGE, app_cpu_info, 71) \ X(a, POINTER, OPTIONAL, MESSAGE, app_mem_info, 73) \ -X(a, POINTER, SINGULAR, UENUM, client_type, 100) +X(a, POINTER, SINGULAR, UENUM, client_type, 100) \ +X(a, POINTER, REPEATED, MESSAGE, clients, 200) #define Message_CALLBACK NULL #define Message_DEFAULT NULL #define Message_alive_MSGTYPE Alive @@ -468,6 +472,7 @@ X(a, POINTER, SINGULAR, UENUM, client_type, 100) #define Message_app_gpu_info_MSGTYPE GpuInfoApp #define Message_app_cpu_info_MSGTYPE CpuInfoApp #define Message_app_mem_info_MSGTYPE MemInfoApp +#define Message_clients_MSGTYPE Message #define Alive_FIELDLIST(X, a) \ X(a, POINTER, SINGULAR, UINT32, dummy, 1) diff --git a/src/server/mangohud.proto b/src/server/mangohud.proto index ef09419..92d8523 100644 --- a/src/server/mangohud.proto +++ b/src/server/mangohud.proto @@ -88,6 +88,11 @@ message Message { CpuInfoApp app_cpu_info = 71; // I.e. CPU usage and number of threads by app. MemInfoApp app_mem_info = 73; // I.e. MEM, stack, swap used by app. + + // This is sent to GUI client when they ask for info about all + // connected clients. + repeated Message clients = 200; + // Note. }; diff --git a/src/server/meson.build b/src/server/meson.build new file mode 100644 index 0000000..e716349 --- /dev/null +++ b/src/server/meson.build @@ -0,0 +1,58 @@ +cmake = import('cmake') + +nanopb = dependency('nanopb', version : '>=0.4.2', method : 'cmake', modules : ['nanopb::protobuf-nanopb-static'], required : false) +must_regenerate_pb = nanopb.found() +if not nanopb.found() + opt_var = cmake.subproject_options() + opt_var.add_cmake_defines({ + #'-DCMAKE_C_COMPILER=' + , + 'nanopb_BUILD_GENERATOR': true, + 'BUILD_SHARED_LIBS': false, + 'CMAKE_C_FLAGS': '-DPB_ENABLE_MALLOC', + 'CMAKE_POSITION_INDEPENDENT_CODE': true, + }) + nanopb_proj = cmake.subproject('nanopb', options: opt_var) + nanopb = nanopb_proj.dependency('protobuf-nanopb-static') +endif + +rpc_common_sources = files('common.c') + +if must_regenerate_pb + protoc = find_program('protoc') + protoc_gen_nanopb = find_program('protoc-gen-nanopb') + + gen_pb_py = meson.current_source_dir() + '/gen-pb.py' + + mangohud_pb = custom_target('gen-pb', + input : ['mangohud.proto', 'mangohud.options'], + output : ['mangohud.pb.c', 'mangohud.pb.h'], + command : [gen_pb_py, protoc.path(), protoc_gen_nanopb.path(), '@INPUT0@', '@INPUT1@', meson.current_build_dir()]) + + rpc_common_sources += mangohud_pb +else + rpc_common_sources += 'mangohud.pb.c' +endif + + +#mangohud_pb = nanopb('mangohud.proto') + +rpc_common = static_library( + 'common', + rpc_common_sources, + c_args : [ + pre_args, + ], + cpp_args : [ + pre_args, + ], + dependencies : [ + nanopb, + ], + #link_args : ['-lprotobuf-nanopb'], +) + +#executable('server', ['server.cpp'], link_with : rpc_common, dependencies : nanopb, install : true) +executable('server', ['server.cpp'], link_with : rpc_common, install : true) +#executable('server', ['server.cpp'], dependencies : [rpc_common, nanopb], install : true) + +#executable('client-demo', ['client_demo.cpp'], link_with : rpc_common, dependencies : nanopb) diff --git a/src/server/protoc-gen-nanopb b/src/server/protoc-gen-nanopb new file mode 100755 index 0000000..841ecf7 --- /dev/null +++ b/src/server/protoc-gen-nanopb @@ -0,0 +1,18 @@ +#!/bin/sh + +# This file is used to invoke nanopb_generator.py as a plugin +# to protoc on Linux and other *nix-style systems. +# Use it like this: +# protoc --plugin=nanopb=..../protoc-gen-nanopb --nanopb_out=dir foo.proto +# +# Note that if you use the binary package of nanopb, the protoc +# path is already set up properly and there is no need to give +# --plugin= on the command line. + +NANOPB_PATH="../../subprojects/nanopb/generator" +if [ -x "${NANOPB_PATH}/nanopb_generator.py" ]; then + exec python3 "${NANOPB_PATH}/nanopb_generator.py" --protoc-plugin +else + # Try in default PATH. + exec "nanopb_generator.py" --protoc-plugin +fi \ No newline at end of file diff --git a/src/server/server.cpp b/src/server/server.cpp index c7a6d00..f961691 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -11,12 +11,16 @@ #include #include #include +#ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS +#endif #include #include +#include - +#ifndef PB_ENABLE_MALLOC #define PB_ENABLE_MALLOC +#endif #include #include #include @@ -180,12 +184,17 @@ static void sigint_handler(int sig, siginfo_t *info, void *ucontext) { static int loop() { // Create local socket. +retry_unix_socket: // int connection_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); - int connection_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (connection_socket == -1) { + int connection_unix_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (connection_unix_socket == -1) { + if (errno == EINTR) { + goto retry_unix_socket; + } return errno; // socket } + { struct sockaddr_un name; memset(&name, 0, sizeof(name)); @@ -195,8 +204,8 @@ static int loop() { strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1); int retry = 1; -retry_bind: - if (bind(connection_socket, (const struct sockaddr *)&name, +retry_unix_bind: + if (bind(connection_unix_socket, (const struct sockaddr *)&name, sizeof(name)) != 0) { if (errno == EADDRINUSE && retry > 0) { retry = 0; @@ -204,28 +213,108 @@ retry_bind: // sizeof(addr)); unlink(SOCKET_NAME); - goto retry_bind; + goto retry_unix_bind; } return errno; // bind } + } + +// AF_INET6 or PF_INET6? + int connection_tcp_socket = socket(AF_INET6, SOCK_STREAM, 0); + if (connection_tcp_socket == -1) { + if (errno == EINTR) { + goto retry_unix_socket; + } + return errno; // socket + } + + { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(sockaddr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(9869); + //addr.sin6_addr = IN6ADDR_ANY_INIT; + addr.sin6_addr = in6addr_any; - if (listen(connection_socket, 20) != 0) { + int retry = 1; +retry_tcp_bind: + if (bind(connection_tcp_socket, (const struct sockaddr *)&addr, + sizeof(addr)) != 0) { + if (errno == EADDRINUSE && retry > 0) { + retry = 0; + //if (connect(data_socket, (const struct sockaddr *) &addr, + // sizeof(addr)); + + goto retry_tcp_bind; + } + return errno; // bind + } + } + + { + int reuse = 1; + setsockopt(connection_tcp_socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + } + + //{ + //int timestamp = 1; + //setsockopt(connection_tcp_socket, SOL_SOCKET, SO_TIMESTAMP, ×tampe, sizeof(timestamp)); + //} + + + if (listen(connection_unix_socket, 20) != 0) { return errno; // listen } + fprintf(stderr, "Listening on UNIX socket %s\n", SOCKET_NAME); + + + if (listen(connection_tcp_socket, 20) != 0) { + return errno; // listen + } + + { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(sockaddr)); + socklen_t addr_len = sizeof(addr); + if (getsockname(connection_tcp_socket, (sockaddr*)&addr, &addr_len) == -1) { + perror("getsockname"); + } + assert(addr_len <= sizeof(addr)); + + char addr_str[INET6_ADDRSTRLEN]; + addr_str[0] = '\0'; + if (inet_ntop(AF_INET6, &addr.sin6_addr, addr_str, sizeof(addr_str))) { + fprintf(stderr, "Listening on TCP socket %s port %d\n", addr_str, ntohs(addr.sin6_port)); + } else { + perror("inet_ntop"); + } + } + int epollfd = epoll_create1(EPOLL_CLOEXEC); if (epollfd < 0) { perror("epoll_create1"); exit(EXIT_FAILURE); } - int dummy_ptr = 0; + int unix_socket_dummy_ptr = 0; + int tcp_socket_dummy_ptr = 0; + + { + struct epoll_event ev; + ev.events = EPOLLIN; + ev.data.ptr = (void*)&unix_socket_dummy_ptr; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connection_unix_socket, &ev) == -1) { + perror("epoll_ctl: connection_socket"); + exit(EXIT_FAILURE); + } + } { struct epoll_event ev; ev.events = EPOLLIN; - ev.data.ptr = (void*)&dummy_ptr; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connection_socket, &ev) == -1) { + ev.data.ptr = (void*)&tcp_socket_dummy_ptr; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connection_tcp_socket, &ev) == -1) { perror("epoll_ctl: connection_socket"); exit(EXIT_FAILURE); } @@ -247,15 +336,98 @@ retry_bind: } for (int n = 0; n < nfds; n++) { - if (events[n].data.ptr == &dummy_ptr) { - int data_socket = accept(connection_socket, NULL, NULL); + if (events[n].data.ptr == &unix_socket_dummy_ptr || + events[n].data.ptr == &tcp_socket_dummy_ptr) { + + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(sockaddr)); + socklen_t addr_size = sizeof(addr); + + int data_socket = + events[n].data.ptr == &unix_socket_dummy_ptr + ? accept(connection_unix_socket, NULL, NULL) + : accept4(connection_tcp_socket, (sockaddr*)&addr, &addr_size, SOCK_CLOEXEC); + +// accept4(connection_tcp_socket, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC); + if (data_socket == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + continue; + } + if (events[n].data.ptr == &tcp_socket_dummy_ptr) { + if (errno == ENETDOWN || errno == EPROTO || + errno == ENOPROTOOPT || errno == EHOSTDOWN || + errno == ENONET || errno == EHOSTUNREACH || + errno == EOPNOTSUPP || errno == ENETUNREACH) { + continue; + } + } +// EPERM Firewall rules forbid connection. (Linux) + perror("accept"); return errno; // accept } fprintf(stderr, "Client connect started\n"); +/* + accept4() is a nonstandard Linux extension. + + On Linux, the new socket returned by accept() does not inherit file + status flags such as O_NONBLOCK and O_ASYNC from the listening + socket. This behavior differs from the canonical BSD sockets + implementation. Portable programs should not rely on inheritance or + noninheritance of file status flags and always explicitly set all + required flags on the socket returned from accept(). + +*/ + if (events[n].data.ptr == &tcp_socket_dummy_ptr) { + char addr_str[INET6_ADDRSTRLEN]; + addr_str[0] = '\0'; + if (inet_ntop(AF_INET6, &addr.sin6_addr, addr_str, sizeof(addr_str))) { + fprintf(stderr, "TCP connection from %s port %d\n", addr_str, ntohs(addr.sin6_port)); + } else { + perror("inet_ntop"); + } + } + + if (events[n].data.ptr == &tcp_socket_dummy_ptr) { + { + int keepalive = 1; + setsockopt(data_socket, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)); + } + + { + struct linger no_linger; + no_linger.l_onoff = 0; + no_linger.l_linger = 0; // seconds + setsockopt(data_socket, SOL_SOCKET, SO_LINGER, &no_linger, sizeof(no_linger)); + } + + { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + socklen_t addr_len = sizeof(addr); + if (getpeername(data_socket, (sockaddr*)&addr, &addr_len) == -1) { + perror("getpeername"); + exit(EXIT_FAILURE); + } + assert(addr_len == sizeof(struct sockaddr_in6)); + + char addr_str[INET6_ADDRSTRLEN]; + addr_str[0] = '\0'; + if (inet_ntop(AF_INET6, &addr.sin6_addr, addr_str, sizeof(addr_str))) { + fprintf(stderr, "TCP connection from %s port %d\n", addr_str, ntohs(addr.sin6_port)); + } else { + perror("inet_ntop"); + } + } + } + +// IP_TOS , IPTOS_LOWDELAY + + + if (set_nonblocking(data_socket)) { goto error_1; } @@ -375,12 +547,18 @@ error_1: } server_states.clear(); - if (close(connection_socket) != 0) { - perror("close: connection_socket"); +close_tcp_socket: + if (close(connection_tcp_socket) != 0) { + perror("close: connection_tcp_socket"); + } + +close_unix_socket: + if (close(connection_unix_socket) != 0) { + perror("close: connection_unix_socket"); } if (unlink(SOCKET_NAME) != 0) { - perror("unlink: socket file"); + perror("unlink: unix_socket file"); } return 0; diff --git a/subprojects/nanopb.wrap b/subprojects/nanopb.wrap new file mode 100644 index 0000000..b36adf6 --- /dev/null +++ b/subprojects/nanopb.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory = nanopb +url = https://github.com/nanopb/nanopb +revision = 0.4.4