diff options
-rw-r--r-- | CMakeLists.txt | 15 | ||||
-rw-r--r-- | build/.gitignore | 5 | ||||
-rw-r--r-- | build/FindGlib.cmake | 42 | ||||
-rw-r--r-- | build/FinxdGlib.cmake | 42 | ||||
-rw-r--r-- | build/Makefile | 258 | ||||
-rw-r--r-- | build/cmake_install.cmake | 44 | ||||
-rw-r--r-- | cmake/FindGIO.cmake | 27 | ||||
-rw-r--r-- | cmake/FindGlib.cmake | 43 | ||||
-rw-r--r-- | cmake/LibFindMacros.cmake | 76 | ||||
-rw-r--r-- | glib-sock-serv.kdev4 | 4 | ||||
-rw-r--r-- | instr-client.c | 143 | ||||
-rw-r--r-- | instr-daemon.c | 267 | ||||
-rw-r--r-- | response.c | 119 | ||||
-rw-r--r-- | response.h | 17 | ||||
-rw-r--r-- | signalobject.c | 38 | ||||
-rw-r--r-- | signalobject.h | 42 | ||||
-rw-r--r-- | socket-common.h | 16 |
17 files changed, 1198 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4d7d8e9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.8) +project(glib-sock-serv) + +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) +find_package(Glib) +find_package(GIO) +include_directories(${GLIB_PKG_INCLUDE_DIRS}) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") +add_executable(instr-daemon instr-daemon.c signalobject.c response.c) +add_executable(instr-client instr-client.c) + +target_link_libraries(instr-daemon gio-2.0) +target_link_libraries(instr-client gio-2.0) + + diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..440dbee --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,5 @@ +MakeCache.txt +CMakeFiles +Makefile +cmake_install.cmake +install_manifest.txt diff --git a/build/FindGlib.cmake b/build/FindGlib.cmake new file mode 100644 index 0000000..f1986c9 --- /dev/null +++ b/build/FindGlib.cmake @@ -0,0 +1,42 @@ +pkg_check_modules(GLIB_PKG glib-2.0) + +if (GLIB_PKG_FOUND) + find_path(GLIB_INCLUDE_DIR NAMES glib.h PATH_SUFFIXES glib-2.0 + PATHS + ${GLIB_PKG_INCLUDE_DIRS} + /usr/include/glib-2.0 + /usr/include + /usr/local/include + ) + find_path(GLIB_CONFIG_INCLUDE_DIR NAMES glibconfig.h PATHS ${GLIB_PKG_LIBDIR} PATH_SUFFIXES glib-2.0/include) + + find_library(GLIB_LIBRARIES NAMES glib-2.0 + PATHS + ${GLIB_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + +else (GLIB_PKG_FOUND) + # Find Glib even if pkg-config is not working (eg. cross compiling to Windows) + find_library(GLIB_LIBRARIES NAMES glib-2.0) + string (REGEX REPLACE "/[^/]*$" "" GLIB_LIBRARIES_DIR ${GLIB_LIBRARIES}) + + find_path(GLIB_INCLUDE_DIR NAMES glib.h PATH_SUFFIXES glib-2.0) + find_path(GLIB_CONFIG_INCLUDE_DIR NAMES glibconfig.h PATHS ${GLIB_LIBRARIES_DIR} PATH_SUFFIXES glib-2.0/include) + +endif (GLIB_PKG_FOUND) + +if (GLIB_INCLUDE_DIR AND GLIB_CONFIG_INCLUDE_DIR AND GLIB_LIBRARIES) + set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIB_CONFIG_INCLUDE_DIR}) +endif (GLIB_INCLUDE_DIR AND GLIB_CONFIG_INCLUDE_DIR AND GLIB_LIBRARIES) + +if(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + set(GLIB_FOUND TRUE CACHE INTERNAL "glib-2.0 found") + message(STATUS "Found glib-2.0: ${GLIB_INCLUDE_DIR}, ${GLIB_LIBRARIES}") +else(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + set(GLIB_FOUND FALSE CACHE INTERNAL "glib-2.0 found") + message(STATUS "glib-2.0 not found.") +endif(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + +mark_as_advanced(GLIB_INCLUDE_DIR GLIB_CONFIG_INCLUDE_DIR GLIB_INCLUDE_DIRS GLIB_LIBRARIES) diff --git a/build/FinxdGlib.cmake b/build/FinxdGlib.cmake new file mode 100644 index 0000000..f1986c9 --- /dev/null +++ b/build/FinxdGlib.cmake @@ -0,0 +1,42 @@ +pkg_check_modules(GLIB_PKG glib-2.0) + +if (GLIB_PKG_FOUND) + find_path(GLIB_INCLUDE_DIR NAMES glib.h PATH_SUFFIXES glib-2.0 + PATHS + ${GLIB_PKG_INCLUDE_DIRS} + /usr/include/glib-2.0 + /usr/include + /usr/local/include + ) + find_path(GLIB_CONFIG_INCLUDE_DIR NAMES glibconfig.h PATHS ${GLIB_PKG_LIBDIR} PATH_SUFFIXES glib-2.0/include) + + find_library(GLIB_LIBRARIES NAMES glib-2.0 + PATHS + ${GLIB_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + +else (GLIB_PKG_FOUND) + # Find Glib even if pkg-config is not working (eg. cross compiling to Windows) + find_library(GLIB_LIBRARIES NAMES glib-2.0) + string (REGEX REPLACE "/[^/]*$" "" GLIB_LIBRARIES_DIR ${GLIB_LIBRARIES}) + + find_path(GLIB_INCLUDE_DIR NAMES glib.h PATH_SUFFIXES glib-2.0) + find_path(GLIB_CONFIG_INCLUDE_DIR NAMES glibconfig.h PATHS ${GLIB_LIBRARIES_DIR} PATH_SUFFIXES glib-2.0/include) + +endif (GLIB_PKG_FOUND) + +if (GLIB_INCLUDE_DIR AND GLIB_CONFIG_INCLUDE_DIR AND GLIB_LIBRARIES) + set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIB_CONFIG_INCLUDE_DIR}) +endif (GLIB_INCLUDE_DIR AND GLIB_CONFIG_INCLUDE_DIR AND GLIB_LIBRARIES) + +if(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + set(GLIB_FOUND TRUE CACHE INTERNAL "glib-2.0 found") + message(STATUS "Found glib-2.0: ${GLIB_INCLUDE_DIR}, ${GLIB_LIBRARIES}") +else(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + set(GLIB_FOUND FALSE CACHE INTERNAL "glib-2.0 found") + message(STATUS "glib-2.0 not found.") +endif(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + +mark_as_advanced(GLIB_INCLUDE_DIR GLIB_CONFIG_INCLUDE_DIR GLIB_INCLUDE_DIRS GLIB_LIBRARIES) diff --git a/build/Makefile b/build/Makefile new file mode 100644 index 0000000..e10303e --- /dev/null +++ b/build/Makefile @@ -0,0 +1,258 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /usr/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /fileserver2/home/mjc/git/Instrument + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /fileserver2/home/mjc/git/Instrument/build + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /usr/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /fileserver2/home/mjc/git/Instrument/build/CMakeFiles /fileserver2/home/mjc/git/Instrument/build/CMakeFiles/progress.marks + $(MAKE) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /fileserver2/home/mjc/git/Instrument/build/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named instr-client + +# Build rule for target. +instr-client: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 instr-client +.PHONY : instr-client + +# fast build rule for target. +instr-client/fast: + $(MAKE) -f CMakeFiles/instr-client.dir/build.make CMakeFiles/instr-client.dir/build +.PHONY : instr-client/fast + +#============================================================================= +# Target rules for targets named instr-daemon + +# Build rule for target. +instr-daemon: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 instr-daemon +.PHONY : instr-daemon + +# fast build rule for target. +instr-daemon/fast: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/build +.PHONY : instr-daemon/fast + +instr-client.o: instr-client.c.o +.PHONY : instr-client.o + +# target to build an object file +instr-client.c.o: + $(MAKE) -f CMakeFiles/instr-client.dir/build.make CMakeFiles/instr-client.dir/instr-client.c.o +.PHONY : instr-client.c.o + +instr-client.i: instr-client.c.i +.PHONY : instr-client.i + +# target to preprocess a source file +instr-client.c.i: + $(MAKE) -f CMakeFiles/instr-client.dir/build.make CMakeFiles/instr-client.dir/instr-client.c.i +.PHONY : instr-client.c.i + +instr-client.s: instr-client.c.s +.PHONY : instr-client.s + +# target to generate assembly for a file +instr-client.c.s: + $(MAKE) -f CMakeFiles/instr-client.dir/build.make CMakeFiles/instr-client.dir/instr-client.c.s +.PHONY : instr-client.c.s + +instr-daemon.o: instr-daemon.c.o +.PHONY : instr-daemon.o + +# target to build an object file +instr-daemon.c.o: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/instr-daemon.c.o +.PHONY : instr-daemon.c.o + +instr-daemon.i: instr-daemon.c.i +.PHONY : instr-daemon.i + +# target to preprocess a source file +instr-daemon.c.i: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/instr-daemon.c.i +.PHONY : instr-daemon.c.i + +instr-daemon.s: instr-daemon.c.s +.PHONY : instr-daemon.s + +# target to generate assembly for a file +instr-daemon.c.s: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/instr-daemon.c.s +.PHONY : instr-daemon.c.s + +response.o: response.c.o +.PHONY : response.o + +# target to build an object file +response.c.o: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/response.c.o +.PHONY : response.c.o + +response.i: response.c.i +.PHONY : response.i + +# target to preprocess a source file +response.c.i: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/response.c.i +.PHONY : response.c.i + +response.s: response.c.s +.PHONY : response.s + +# target to generate assembly for a file +response.c.s: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/response.c.s +.PHONY : response.c.s + +signalobject.o: signalobject.c.o +.PHONY : signalobject.o + +# target to build an object file +signalobject.c.o: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/signalobject.c.o +.PHONY : signalobject.c.o + +signalobject.i: signalobject.c.i +.PHONY : signalobject.i + +# target to preprocess a source file +signalobject.c.i: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/signalobject.c.i +.PHONY : signalobject.c.i + +signalobject.s: signalobject.c.s +.PHONY : signalobject.s + +# target to generate assembly for a file +signalobject.c.s: + $(MAKE) -f CMakeFiles/instr-daemon.dir/build.make CMakeFiles/instr-daemon.dir/signalobject.c.s +.PHONY : signalobject.c.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... instr-client" + @echo "... instr-daemon" + @echo "... rebuild_cache" + @echo "... instr-client.o" + @echo "... instr-client.i" + @echo "... instr-client.s" + @echo "... instr-daemon.o" + @echo "... instr-daemon.i" + @echo "... instr-daemon.s" + @echo "... response.o" + @echo "... response.i" + @echo "... response.s" + @echo "... signalobject.o" + @echo "... signalobject.i" + @echo "... signalobject.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/build/cmake_install.cmake b/build/cmake_install.cmake new file mode 100644 index 0000000..aac7ddf --- /dev/null +++ b/build/cmake_install.cmake @@ -0,0 +1,44 @@ +# Install script for directory: /fileserver2/home/mjc/git/Instrument + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + +# Install shared libraries without execute permission? +IF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + SET(CMAKE_INSTALL_SO_NO_EXE "0") +ENDIF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + +IF(CMAKE_INSTALL_COMPONENT) + SET(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") +ELSE(CMAKE_INSTALL_COMPONENT) + SET(CMAKE_INSTALL_MANIFEST "install_manifest.txt") +ENDIF(CMAKE_INSTALL_COMPONENT) + +FILE(WRITE "/fileserver2/home/mjc/git/Instrument/build/${CMAKE_INSTALL_MANIFEST}" "") +FOREACH(file ${CMAKE_INSTALL_MANIFEST_FILES}) + FILE(APPEND "/fileserver2/home/mjc/git/Instrument/build/${CMAKE_INSTALL_MANIFEST}" "${file}\n") +ENDFOREACH(file) diff --git a/cmake/FindGIO.cmake b/cmake/FindGIO.cmake new file mode 100644 index 0000000..c32a3bf --- /dev/null +++ b/cmake/FindGIO.cmake @@ -0,0 +1,27 @@ +# - Try to find GIO 2.0 +# Once done, this will define +# +# GIO_FOUND - system has GIO +# GIO_INCLUDE_DIRS - the GIO include directories +# GIO_LIBRARIES - link these to use GIO + +include(LibFindMacros) + +# Dependencies +libfind_package(GIO Glib) + +# Use pkg-config to get hints about paths +libfind_pkg_check_modules(GIO_PKGCONF gio-2.0) + +# Find the library +find_library(GIO_LIBRARY + NAMES gio-2.0 + PATHS ${GIO_PKGCONF_LIBRARY_DIRS} +) + +# Set the include dir variables and the libraries and let libfind_process do the rest. +# NOTE: Singular variables for this library, plural for libraries this this lib depends on. +set(GIO_PROCESS_INCLUDES Glib_INCLUDE_DIRS) +set(GIO_PROCESS_LIBS GIO_LIBRARY Glib_LIBRARIES) +libfind_process(GIO) + diff --git a/cmake/FindGlib.cmake b/cmake/FindGlib.cmake new file mode 100644 index 0000000..cddc9f0 --- /dev/null +++ b/cmake/FindGlib.cmake @@ -0,0 +1,43 @@ +find_package(PkgConfig) +pkg_check_modules(GLIB_PKG glib-2.0) + +if (GLIB_PKG_FOUND) + find_path(GLIB_INCLUDE_DIR NAMES glib.h PATH_SUFFIXES glib-2.0 + PATHS + ${GLIB_PKG_INCLUDE_DIRS} + /usr/include/glib-2.0 + /usr/include + /usr/local/include + ) + find_path(GLIB_CONFIG_INCLUDE_DIR NAMES glibconfig.h PATHS ${GLIB_PKG_LIBDIR} PATH_SUFFIXES glib-2.0/include) + + find_library(GLIB_LIBRARIES NAMES glib-2.0 + PATHS + ${GLIB_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + +else (GLIB_PKG_FOUND) + # Find Glib even if pkg-config is not working (eg. cross compiling to Windows) + find_library(GLIB_LIBRARIES NAMES glib-2.0) + string (REGEX REPLACE "/[^/]*$" "" GLIB_LIBRARIES_DIR ${GLIB_LIBRARIES}) + + find_path(GLIB_INCLUDE_DIR NAMES glib.h PATH_SUFFIXES glib-2.0) + find_path(GLIB_CONFIG_INCLUDE_DIR NAMES glibconfig.h PATHS ${GLIB_LIBRARIES_DIR} PATH_SUFFIXES glib-2.0/include) + +endif (GLIB_PKG_FOUND) + +if (GLIB_INCLUDE_DIR AND GLIB_CONFIG_INCLUDE_DIR AND GLIB_LIBRARIES) + set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIB_CONFIG_INCLUDE_DIR}) +endif (GLIB_INCLUDE_DIR AND GLIB_CONFIG_INCLUDE_DIR AND GLIB_LIBRARIES) + +if(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + set(GLIB_FOUND TRUE CACHE INTERNAL "glib-2.0 found") + message(STATUS "Found glib-2.0: ${GLIB_INCLUDE_DIR}, ${GLIB_LIBRARIES}") +else(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + set(GLIB_FOUND FALSE CACHE INTERNAL "glib-2.0 found") + message(STATUS "glib-2.0 not found.") +endif(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES) + +mark_as_advanced(GLIB_INCLUDE_DIR GLIB_CONFIG_INCLUDE_DIR GLIB_INCLUDE_DIRS GLIB_LIBRARIES) diff --git a/cmake/LibFindMacros.cmake b/cmake/LibFindMacros.cmake new file mode 100644 index 0000000..83b68b5 --- /dev/null +++ b/cmake/LibFindMacros.cmake @@ -0,0 +1,76 @@ +# Works the same as find_package, but forwards the "REQUIRED" argument used for +# the current package and always uses the "QUIET" flag. For this to work, the +# first parameter must be the prefix of the current package, then the prefix of +# the new package etc, which are passed to find_package. +macro (libfind_package PREFIX) + set (LIBFIND_PACKAGE_ARGS ${ARGN} QUIET) + if (${PREFIX}_FIND_REQUIRED) + set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) + endif (${PREFIX}_FIND_REQUIRED) + find_package(${LIBFIND_PACKAGE_ARGS}) +endmacro (libfind_package) + +# Damn CMake developers made the UsePkgConfig system deprecated in the same release (2.6) +# where they added pkg_check_modules. Consequently I need to support both in my scripts +# to avoid those deprecated warnings. Here's a helper that does just that. +# Works identically to pkg_check_modules, except that no checks are needed prior to use. +macro (libfind_pkg_check_modules PREFIX PKGNAME) + if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + include(UsePkgConfig) + pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) + else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(${PREFIX} ${PKGNAME}) + endif (PKG_CONFIG_FOUND) + endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) +endmacro (libfind_pkg_check_modules) + +# Do the final processing once the paths have been detected. +# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain +# all the variables, each of which contain one include directory. +# Ditto for ${PREFIX}_PROCESS_LIBS and library files. +# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. +# Also handles errors in case library detection was required, etc. +macro (libfind_process PREFIX) + # Skip processing if already processed during this run + if (NOT ${PREFIX}_FOUND) + # Start with the assumption that the library was found + set (${PREFIX}_FOUND TRUE) + + # Process all includes and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_INCLUDES}) + if (${i}) + set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + + # Process all libraries and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_LIBS}) + if (${i}) + set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + + # Print message and/or exit on fatal error + if (${PREFIX}_FOUND) + if (NOT ${PREFIX}_FIND_QUIETLY) + message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") + endif (NOT ${PREFIX}_FIND_QUIETLY) + else (${PREFIX}_FOUND) + if (${PREFIX}_FIND_REQUIRED) + foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) + message("${i}=${${i}}") + endforeach (i) + message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") + endif (${PREFIX}_FIND_REQUIRED) + endif (${PREFIX}_FOUND) + endif (NOT ${PREFIX}_FOUND) +endmacro (libfind_process) + diff --git a/glib-sock-serv.kdev4 b/glib-sock-serv.kdev4 new file mode 100644 index 0000000..a827316 --- /dev/null +++ b/glib-sock-serv.kdev4 @@ -0,0 +1,4 @@ +[Project] +Name=glib-sock-serv +Manager=KDevCMakeManager +VersionControl= diff --git a/instr-client.c b/instr-client.c new file mode 100644 index 0000000..0269f61 --- /dev/null +++ b/instr-client.c @@ -0,0 +1,143 @@ +#include <stdio.h> +#include <gio/gio.h> +#include <string.h> +#include "response.h" +#include <stdlib.h> +#include <strings.h> + +static int port = 3333; +#define BUFSIZE 1024 + +GMainContext *context=NULL; +GMainLoop *mainLoop=NULL; +GSocketConnection * connection = NULL; +GSocketClient * client = NULL; + +char exitTokens[5][7] = {"quit", "exit", "logout", "logoff", "local"}; + +//helper function to nicely terminate the client +static void terminate(char *message, int exitCode) +{ + g_object_unref(client); + g_object_unref(connection); + if (message) { + g_print("%s\n", message); + } + exit(exitCode); +} + +//a sort of strncmp but with \n or \r exception +static gboolean Matches(char *src, char* dst, gssize size) +{ + for(; *src != '\0', (size--)>0; src++) { + if(g_ascii_toupper(*src) != g_ascii_toupper(*dst)) { + return FALSE; + } + dst++; + } + for(; *dst != '\0'; dst++) + if (*dst != '\r' && *dst != '\n') { + return FALSE; + } + + return TRUE; +} + + +//GIOChannel callback +static gboolean +stdinAvailable (GIOChannel *source, GIOCondition condition, gpointer data) +{ + char tmp[BUFSIZE]; + memset(tmp,0,BUFSIZE); + int size = read(0, tmp, BUFSIZE); + if(size<=0) { + return TRUE; + } + + //test if we have an exit word + int idx=0; + for(idx=0; idx<sizeof(exitTokens)/sizeof(exitTokens[0]); idx++) { + if(Matches(exitTokens[idx], tmp, strlen(exitTokens[idx]))) { + g_socket_close(g_socket_connection_get_socket(connection), NULL); + terminate("Goodbye", 0); + } + } + + //write the message + gssize written=0; + GPollableOutputStream* out = (GPollableOutputStream*)data; + written = g_pollable_output_stream_write_nonblocking(out, tmp, size, NULL, NULL); + if (written <=0 || written == G_IO_ERROR_WOULD_BLOCK) { + return FALSE; + } + + return TRUE; +} + +//callback for server input +static gboolean cbServerInput(gpointer data, gpointer additional) +{ + char buffer[BUFSIZE]; + gssize size=0; + memset(buffer,0,BUFSIZE); + + GPollableInputStream* inStream = (GPollableInputStream*)data; + + size=g_pollable_input_stream_read_nonblocking(inStream, buffer, BUFSIZE, NULL, NULL); + if(size <=0 || size == G_IO_ERROR_WOULD_BLOCK) { + terminate("Connection to server lost", -1); + } + g_print("\n%s", buffer); + g_print("> "); + return TRUE; +} + +int main(int argc, char** argv) +{ + /* create a new connection */ + g_type_init (); + + GOutputStream *out; + GInputStream *in; + GError* error = NULL; + GIOChannel* stdinChannel = NULL; + client = g_socket_client_new(); + GSource *source = NULL; + + /* connect to the host */ + connection = g_socket_client_connect_to_host (client, + (gchar*)"localhost", + port, + NULL, + &error); + + if (error != NULL) { + g_print("Could not connect to server on port %d\n", port); + g_object_unref(client); + return -1; + } + g_print("> "); + + + //register Pollable sources + out = g_io_stream_get_output_stream (G_IO_STREAM (connection)); + in = g_io_stream_get_input_stream (G_IO_STREAM (connection)); + GSource *outSource = NULL; + GSource *inSource = g_pollable_input_stream_create_source((struct GPollableInputStream*)in, NULL); + outSource = g_pollable_output_stream_create_source((struct GPollableOutputStream*)out, NULL); + + //register stdin channel + stdinChannel = g_io_channel_unix_new(0); + if(stdinChannel == NULL) { + terminate("Could not open STDIN channel", -2); + } + + //attach the sources + g_io_add_watch(stdinChannel, G_IO_IN, stdinAvailable, (struct GPollableOutputStream*)out); + g_source_set_callback(inSource, cbServerInput, (GPollableOutputStream*)in, NULL); + + g_source_attach(inSource, NULL); + g_main_loop_run (g_main_loop_new (NULL, FALSE)); + return 0; +}
\ No newline at end of file diff --git a/instr-daemon.c b/instr-daemon.c new file mode 100644 index 0000000..21864f7 --- /dev/null +++ b/instr-daemon.c @@ -0,0 +1,267 @@ +#include "socket-common.h" +#include "response.h" +#include <stdlib.h> +#include <ctype.h> + +#define STDIN_BUF_SIZE 1024 + +int port=3333; //port to listen +int connections=0; +int maxConn=16; //max connections - 16 + +guint signalMyCb; //signal to register which is used in cbClientInput(), step 10 from requirements +GAsyncQueue** stdinQueue=NULL; +GThread **peers; //actual connected peers + + +//GIOChannel callback for stdin +static gboolean +stdinAvailable (GIOChannel *source, GIOCondition condition, gpointer data) +{ + static char* buffer=NULL; + static gint64 allocated=0; + GAsyncQueue* queue=NULL; + + //temporary buffer to read from stdin + char tmp[STDIN_BUF_SIZE]; + memset(tmp,0,STDIN_BUF_SIZE); + + int size = read(0, tmp, STDIN_BUF_SIZE); + if(size<=0) { + return TRUE; + } + + //fix for \n or \r sending + if(size ==1) + if(tmp[0] == '\r' || tmp[0] == '\n') { + return TRUE; + } + + //the termination characters + if(!strncmp(tmp, "..", size-1)) { + //final reallocation of the buffer to accomodate the whole string + buffer=realloc(buffer,allocated+1); + buffer[allocated] = '\0'; + int idx=0; + + g_print_debug("Got the buffer: \"%s\", tid: %p\n", buffer, g_thread_self()); + + if (tmp[0] == '.' && tmp[1] == '.') { //fix for single dot sending + int count=0; + + //send the final buffer to the queue + for(count=0; count<maxConn; count++) { + //allocate on the heap and deallocate in response.c, cbClientOutput() + char *toSend = realloc(NULL, allocated+1); + memcpy(toSend, buffer, allocated+1); + + //make sure we send to only valid peers + if(peers[count] != 0) { + g_async_queue_push(stdinQueue[count], toSend); + } + } + + //free the buffer + free(buffer); + buffer=NULL; + allocated=0; + return TRUE; + } + } + + //allocate on the heap. buffer is NULL the first time + buffer=realloc(buffer, allocated+size); + memcpy(buffer+allocated, tmp, size); + allocated += size; //keep track of allocation + + + return TRUE; +} + +/** pulls an integer position from the vector which contains the + position to use for the stdinQueue vector + @param id - the thread id +*/ +static int pullIndex(GThread* id) +{ + int i=0,ret=-1; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + g_static_mutex_lock (&mutex); + for(i=0; i<maxConn; i++) + if(peers[i] == id) { + peers[i] = (GThread*)0; + ret=i; + break; + } + g_static_mutex_unlock (&mutex); + return ret; +} + +/** + * pushed in the peers vector the thread id for future reference + * @param id + */ +static int pushIndex(GThread* id) +{ + int i=0,ret=-1; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + g_static_mutex_lock (&mutex); + for(i=0; i<maxConn; i++) + if(peers[i] == 0) { + peers[i] = id; + ret=i; + break; + } + + g_static_mutex_unlock (&mutex); + return ret; +} + +//handler for incoming connection, closes the connection if maxCon connections are already handled +static gboolean +incomingConnection (GSocketService *service, + GSocketConnection *connection, + GSocketListener *listener, + gpointer user_data) +{ + if(connections +1 > maxConn) { + g_print_debug("Connection closed. Max reached\n"); + return TRUE; + } + connections++; + g_print_debug("Incoming connection\n"); + return FALSE; +} + + +//thread connection handler +static gboolean +handler (GThreadedSocketService *service, + GSocketConnection *connection, + GSocketListener *listener, + gpointer user_data) +{ + + + GOutputStream *out; + GInputStream *in; + gssize size; + + + out = g_io_stream_get_output_stream (G_IO_STREAM (connection)); + in = g_io_stream_get_input_stream (G_IO_STREAM (connection)); + + g_print_debug("Handling, connections: %d\n", connections); + + //register ourselves in the peers vector, use the index obtained in the stdinQueue + //should not get -1 + GThread* self = g_thread_self(); + int index=pushIndex(self); + + GSource *outSource = NULL; + GSource *inSource = g_pollable_input_stream_create_source((struct GPollableInputStream*)in, NULL); + + //get a reference to the async queue + GAsyncQueue *queue = g_async_queue_ref(stdinQueue[index]); + + //input from client + g_source_set_callback(inSource, cbClientInput, (GPollableOutputStream*)out, NULL); + g_source_attach(inSource, NULL); + + //keep thread alive, every 1000 microseconds + while(g_source_is_destroyed(inSource)==FALSE) { + g_usleep(1000); + gint elems; + + //verify our queue length and activate/deactivate the "out" Source for this connection + //if we don't do this, the out Source will be scheduled frequently and will busy loop + if((elems=g_async_queue_length(queue))>0) { + if(outSource == NULL) { + + outSource = g_pollable_output_stream_create_source((struct GPollableOutputStream*)out, NULL); + g_source_set_callback(outSource, cbClientOutput, queue, NULL); + g_source_attach(outSource, NULL); + } else { + g_source_destroy(outSource); + g_source_unref(outSource); + outSource = NULL; + } + + } else { + if(outSource!= NULL && !g_source_is_destroyed(outSource)) { + g_print_debug("Destroy source\n"); + g_source_destroy(outSource); + g_source_unref(outSource); + outSource = NULL; //added + } + } + //end of activate/deactivate + } + + //reached the end of the thread + if (g_output_stream_close(out, NULL, NULL) == FALSE) { + g_print_debug("out not closed\n"); + } + if (g_input_stream_close(in, NULL, NULL) == FALSE) { + g_print_debug("in not closed\n"); + } + + g_print_debug("Thread end\n"); + connections--; //keep track of connections + g_async_queue_unref(queue); //unreference the queue + pullIndex(g_thread_self()); //unregister from the peers vector + return TRUE; +} + +int main(int argc, char **argv) +{ + GSocketService *service = NULL; + GError *error = NULL; + GIOChannel* stdinChannel = NULL; + + g_type_init (); + + //register stdin channel + stdinChannel = g_io_channel_unix_new(0); + if(stdinChannel == NULL) { + g_printerr("No io channel\n"); + exit(-1); + } + g_io_add_watch(stdinChannel, G_IO_IN, stdinAvailable, NULL); + int idx=0; + + //allocate a maxConn queue on the heap + stdinQueue = malloc(sizeof(struct GAsyncQueue*) * maxConn); + //allocate peers vector on the heap + peers = malloc(sizeof(GThread*) * maxConn); + for(idx=0; idx<maxConn; idx++) { + peers[idx] = 0; + stdinQueue[idx] = g_async_queue_new(); + } + + //create a threaded service + service = g_threaded_socket_service_new (maxConn+1); + if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service), + port, + NULL, + &error)) { + g_printerr ("%s: %s\n", argv[0], error->message); + free(stdinQueue); + free(peers); + return 1; + } + + //init the signal signalMyCb + initSignals(&signalMyCb); + + g_print_debug("Server listening on port %d\n", port); + g_signal_connect (service, "run", G_CALLBACK (handler), NULL); + g_signal_connect (service, "incoming", G_CALLBACK(incomingConnection), NULL); + + g_main_loop_run (g_main_loop_new (NULL, FALSE)); + free(stdinQueue); + free(peers); + + return 0; + +} diff --git a/response.c b/response.c new file mode 100644 index 0000000..1246f0b --- /dev/null +++ b/response.c @@ -0,0 +1,119 @@ +#include "response.h" +#include "socket-common.h" +#include <string.h> + +//RESPONSE related functions from the server + +extern guint signalMyCb; //signal id +extern GAsyncQueue* stdinQueue; //our queue +SignalObject* signalObject; //the signal object which registered the signal id + +//write output to client +static gssize writeOutput(GPollableOutputStream* stream, gchar* data, gssize size); + +//callback for client output, this is where the queue messages are sent to the client +gboolean cbClientOutput(gpointer data, gpointer additional) +{ + GPollableOutputStream* outStream = (GPollableOutputStream*)data; + GAsyncQueue* queue = (GAsyncQueue*)additional; + if(g_async_queue_length(queue) <= 0) { + return FALSE; + } + + gpointer elem; + g_print_debug("Try pop\n"); + //try to pop an element from the queue + elem=g_async_queue_try_pop(queue); + g_print_debug("after pop\n"); + if(elem) { + char* buf = (char*)elem; + g_print_debug("Extracted %s\n", buf); + gssize size = strlen(buf); + gssize written = 0; + + written=g_pollable_output_stream_write_nonblocking(outStream, buf, size+1, NULL, NULL); + if(written==-1) { + g_printerr("Could not write to client\n"); + } + + //free the alloc'ed memory + free(buf); + } + + return FALSE; +} + +//the client input callback +gboolean cbClientInput(gpointer data, gpointer additional) +{ + + char buffer[1024]; + gssize size=0; + memset(buffer,0,1024); + + GPollableInputStream* inStream = (GPollableInputStream*)data; + GPollableOutputStream* outStream = (GPollableOutputStream*)additional; + + size=g_pollable_input_stream_read_nonblocking(inStream, buffer, 1024, NULL, NULL); + if(size <=0 || size == G_IO_ERROR_WOULD_BLOCK) { + g_print_debug("Got: %d\n", size); + return FALSE; + } + + //emit a signal which calls the echoCb function + SignalObjectClass myStruct; + myStruct.instance = NULL; + myStruct.cb = writeOutput; + myStruct.data = buffer; + myStruct.size = size; + myStruct.inStream = inStream; + myStruct.outStream = outStream; + g_signal_emit(signalObject, signalMyCb, 0, &myStruct, NULL); + + return TRUE; +} + +//write output to client +static gssize writeOutput(GPollableOutputStream* stream, gchar* data, gssize size) +{ + gssize what=0; + what=g_pollable_output_stream_write_nonblocking(stream, data, size, NULL, NULL); + if(what < 0 || what == G_IO_ERROR_WOULD_BLOCK) { + return -1; + } + return what; +} + +//initialize the signals +void initSignals(guint *signal) +{ + *signal = g_signal_new("runEchoService", SIGNAL_OBJECT_TYPE, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__POINTER , G_TYPE_NONE, 1, G_TYPE_POINTER); + + signalObject = g_object_new(SIGNAL_OBJECT_TYPE, NULL); + g_signal_connect (signalObject, "runEchoService", G_CALLBACK (echoCb), NULL); +} + +//echo 3 times and send to client one time +void echoCb(gpointer instance, GObject *arg1, gpointer user_data) +{ + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + g_static_mutex_lock (&mutex); + SignalObjectClass *data = (SignalObjectClass*)arg1; + GPollableOutputStream* stream = (GPollableOutputStream*)data->outStream; + gchar* str = data->data; + gssize len = data->size; + gssize written = 0; + + gchar* upper = g_ascii_strup(str, len); + int i; + for(i=0; i<3; i++) { + g_print("%s\n", upper); + } + //send response back to client + + written = data->cb(stream, upper, len); + + g_free(upper); + g_static_mutex_unlock (&mutex); +} diff --git a/response.h b/response.h new file mode 100644 index 0000000..6fca57c --- /dev/null +++ b/response.h @@ -0,0 +1,17 @@ +#include <gio/gio.h> +#include <glibconfig.h> +#include <glib.h> +#include "signalobject.h" + + +typedef struct _streamStruct { + GPollableInputStream* in; + GPollableOutputStream* out; +} streamStruct; + +void echoCb(gpointer instance, GObject *arg1, gpointer user_data); + +gboolean cbClientInput(gpointer data, gpointer additional); +gboolean cbClientOutput(gpointer data, gpointer additional); +void initSignals(guint *signal); +void echoCb(gpointer instance, GObject *arg1, gpointer user_data);
\ No newline at end of file diff --git a/signalobject.c b/signalobject.c new file mode 100644 index 0000000..fe3b7d4 --- /dev/null +++ b/signalobject.c @@ -0,0 +1,38 @@ +#include "signalobject.h" + +G_DEFINE_TYPE (SignalObject, signal_object, G_TYPE_OBJECT); + +static GObject * +signal_object_constructor (GType gtype, + guint n_properties, + GObjectConstructParam *properties) +{ + GObject *obj; + + { + /* Always chain up to the parent constructor */ + obj = G_OBJECT_CLASS (signal_object_parent_class)->constructor (gtype, n_properties, properties); + } + + /* update the object state depending on constructor properties */ + + return obj; +} + + +static void +signal_object_class_init (SignalObjectClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->constructor = signal_object_constructor; +} + + +static void +signal_object_init (SignalObject *self) +{ + /* initialize the object */ +} + + diff --git a/signalobject.h b/signalobject.h new file mode 100644 index 0000000..dedb9b8 --- /dev/null +++ b/signalobject.h @@ -0,0 +1,42 @@ +#ifndef SIGNAL_OBJECT_H +#define SIGNAL_OBJECT_H + +#include <gio/gio.h> +#include <glibconfig.h> +#include <glib.h> + + +#define SIGNAL_OBJECT_TYPE (signal_object_get_type ()) +/* +#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) +#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) +#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) +#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) +#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) +*/ + +typedef struct _SignalObject SignalObject; +typedef struct _SignalObjectClass SignalObjectClass; + + +struct _SignalObject { + GObject parentInstance; + gpointer instance; + gssize (*cb)(GPollableOutputStream* stream, gchar* data, gssize size); + GPollableInputStream* inStream; + GPollableOutputStream* outStream; + gchar* data; + gssize size; +}; + +struct _SignalObjectClass { + GObjectClass parent_class; + gpointer instance; + gssize (*cb)(GPollableOutputStream* stream, gchar* data, gssize size); + GPollableInputStream* inStream; + GPollableOutputStream* outStream; + gchar* data; + gssize size; +}; + +#endif diff --git a/socket-common.h b/socket-common.h new file mode 100644 index 0000000..41d177e --- /dev/null +++ b/socket-common.h @@ -0,0 +1,16 @@ +#ifndef SOCKET_COMMON_H +#define SOCKET_COMMON_H + +#include <stdio.h> +#include <gio/gio.h> +#include <string.h> + +//#define DEBUG_ON - uncomment this to have debug messages + +#ifdef DEBUG_ON +#define g_print_debug(...) g_print(__VA_ARGS__) +#else +#define g_print_debug(...) {} +#endif + +#endif
\ No newline at end of file |