EGong

An UDP Multicast messaging application
git clone git://xatko.vsos.ethz.ch/EGong.git
Log | Files | Refs

commit afb8588cf7ed1b14f8ef500287086e3669b16ac7
Author: Dominik Schmidt <das1993@hotmail.com>
Date:   Sun,  1 Jun 2014 13:45:41 +0200

Initial commit

Diffstat:
.gitignore | 2++
CMakeLists.txt | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/CNC.h | 18++++++++++++++++++
include/EGong | 2++
include/Interfaces.h | 37+++++++++++++++++++++++++++++++++++++
include/Interfaces/Audio.h | 6++++++
include/Interfaces/CMD.h | 27+++++++++++++++++++++++++++
include/Interfaces/GTK.h | 17+++++++++++++++++
include/Interfaces/GTK/Message.h | 2++
include/Interfaces/GTK/NewMessage.h | 8++++++++
include/Interfaces/GTK/TrayIcon.h | 13+++++++++++++
include/Interfaces/STDIO.h | 7+++++++
include/Interfaces/Windows.h | 8++++++++
include/Packet.h | 31+++++++++++++++++++++++++++++++
include/Util/Command.h | 44++++++++++++++++++++++++++++++++++++++++++++
include/Util/Config.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
include/Util/Config_Compiletime.h | 4++++
include/Util/Config_Compiletime.h.in | 4++++
include/Util/File.h | 1+
include/Util/Log.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/Util/Misc.h | 20++++++++++++++++++++
include/Util/Socket.h | 22++++++++++++++++++++++
include/Util/Waiter.h | 13+++++++++++++
src/CNC.c | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/EGong | 0
src/EGong.c | 32++++++++++++++++++++++++++++++++
src/Interfaces.c | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Interfaces/Audio.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Interfaces/CMD.c | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Interfaces/GTK.c | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Interfaces/GTK/Message.c | 19+++++++++++++++++++
src/Interfaces/GTK/NewMessage.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
src/Interfaces/GTK/TrayIcon.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
src/Interfaces/STDIO.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Interfaces/Windows.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Packet.c | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Util/Command.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Util/Config.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Util/File.c | 25+++++++++++++++++++++++++
src/Util/Log.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Util/Misc.c | 12++++++++++++
src/Util/Socket.c | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Util/Waiter.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
43 files changed, 2164 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,2 @@ +build/ +*.o diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -0,0 +1,105 @@ +cmake_minimum_required (VERSION 2.6) +function(addlib lib) + GET_FILENAME_COMPONENT(libn ${lib} NAME) + STRING(REPLACE "/" "_" libn ${lib}) + add_library("${libn}" "${EGONG_SRCDIR}/${lib}.c") + target_link_libraries(EGong "${libn}") +endfunction(addlib) +macro(absolute_libs dest libs) + foreach(lib ${libs}) + if(NOT EXISTS ${lib}) + find_library(ABS_${lib} ${lib}) + if(NOT ABS_${lib} STREQUAL "ABS_${lib}-NOTFOUND") + set(${dest} ${${dest}} ${ABS_${lib}}) + endif() + else(EXISTS ${lib}) + set(${dest} ${${dest}} ${lib}) + endif() + endforeach(lib) +endmacro(absolute_libs) + +macro(include_pkgconfig) +include(/mnt/Share/Programme/SelfBuilt/C/EGong/utils/CMakeModules/FindPkgConfig.cmake) +endmacro(include_pkgconfig) + +macro(EGong_link_libs libs) + set(EGONG_EXT_LIBS "${EGONG_EXT_LIBS}${libs};") +endmacro(EGong_link_libs) + +project(EGong) +set(EGong_VERSION_MAJOR 0) +set(EGong_VERSION_MINOR 1) +set(EGONG_SRCDIR src/) +set(EGONG_LIBS Interfaces/CMD Util/Command Interfaces Interfaces/STDIO CNC Util/Config Util/Socket Packet Util/Waiter Util/Log Util/Misc) +set(EGONG_EXT_LIBS) +include_directories("${PROJECT_SOURCE_DIR}/include") +configure_file( + "${PROJECT_SOURCE_DIR}/include/Util/Config_Compiletime.h.in" + "${PROJECT_SOURCE_DIR}/include/Util/Config_Compiletime.h" +) +add_definitions(-std=gnu99) +if(CMAKE_FIND_ROOT_PATH) + link_directories(${CMAKE_FIND_ROOT_PATH}/usr/lib) +endif(CMAKE_FIND_ROOT_PATH) + +option(USE_GTK "Compile an interface for GTK" OFF) +option(USE_AO "Compile an interface for Audio" OFF) +option(USE_WINGUI "Compile an interface for the Windows GUI-Shell" OFF) + +add_executable(EGong src/EGong.c) + +if(USE_GTK) + find_package(GTK2) + if(GTK2_FOUND) + set(EGONG_LIBS ${EGONG_LIBS} Interfaces/GTK Interfaces/GTK/Message Interfaces/GTK/TrayIcon Interfaces/GTK/NewMessage) + include_directories(${GTK2_INCLUDE_DIRS}) + EGong_link_libs("${GTK2_LIBRARIES}") + Message("${GTK2_LIBRARIES} vs ${EGONG_EXT_LIBS}") + else(NOT GTK2_FOUND) + set(USE_GTK OFF) + endif(GTK2_FOUND) +endif(USE_GTK) + +if(USE_AO) + find_package(PkgConfig) + if(PKGCONFIG_FOUND) + pkg_check_modules(LIBAO ao) + if(LIBAO_FOUND) + set(EGONG_LIBS ${EGONG_LIBS} Interfaces/Audio) + include_directories(${LIBAO_INCLUDE_DIRS}) + EGong_link_libs("${LIBAO_LIBRARIES} m") + else(NOT LIBAO_FOUND) + set(USE_AO OFF) + endif(LIBAO_FOUND) + endif(PKGCONFIG_FOUND) +endif(USE_AO) + +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + EGong_link_libs("ws2_32") + if(USE_WINGUI) + set(EGONG_LIBS ${EGONG_LIBS} Interfaces/Windows) + EGong_link_libs("gdi32 wldap32") + endif(USE_WINGUI) +endif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + +find_package(OpenSSL REQUIRED) +include_directories(${OPENSSL_INCLUDE_DIRS}) +target_link_libraries(EGong ${OPENSSL_LIBRARIES}) + + +foreach(lib ${EGONG_LIBS}) + addlib(${lib}) +endforeach(lib) +target_link_libraries(EGong ${EGONG_EXT_LIBS}) + + +#INSTALL +install(TARGETS EGong DESTINATION bin) + +#PACKING +absolute_libs(ABS_LIBS "${OPENSSL_LIBRARIES};${LIBAO_LIBRARIES}") +set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${ABS_LIBS}) +include (InstallRequiredSystemLibraries) +set (CPACK_PACKAGE_VERSION_MAJOR "${EGong_VERSION_MAJOR}") +set (CPACK_PACKAGE_VERSION_MINOR "${EGong_VERSION_MINOR}") +include (CPack) diff --git a/include/CNC.h b/include/CNC.h @@ -0,0 +1,18 @@ +#pragma once + + +extern int EGong_cnc_init(unsigned int requirements); +extern int EGong_cnc_sendmessage(const char *msg, const char *dest); +extern int EGong_cnc_getmessage(char **msg); +extern void EGong_cnc_freemessage(char *msg); +extern void EGong_cnc_deinit(void); +extern int EGong_cnc_sendmessage_broad(const char *msg); + +enum EGONG_INTERFACE_REQUIREMENTS{ + EGONG_REQUIREMENT_NONE=(0), + EGONG_REQUIREMENT_LISTENER=(1<<0), + EGONG_REQUIREMENT_SOCKETS=(1<<1), + EGONG_REQUIREMENT_TERMINAL=(1<<2), + EGONG_REQUIREMENT_GTK=(1<<3), + EGONG_REQUIREMENT_ALL=(~0) +}; diff --git a/include/EGong b/include/EGong @@ -0,0 +1 @@ +./+ \ No newline at end of file diff --git a/include/Interfaces.h b/include/Interfaces.h @@ -0,0 +1,37 @@ +#pragma once +#include <EGong/CNC.h> + + +enum EGONG_INTERFACE_STATE{ + EGONG_INTERFACE_ACTIVE=(1<<0), + EGONG_INTERFACE_SETUP=(1<<1) +}; + +struct EGong_interface{ + char *name; + char identifier; + unsigned int requirements; + unsigned short int state; + int(*setup)(struct EGong_interface *interface); + int(*shutdown)(struct EGong_interface *interface); + int(*display_message)(struct EGong_interface *interface, const char *msg); + int(*cycle)(struct EGong_interface *interface, char **msg, char **dest); +}; +extern unsigned short int EGong_interfaces_userstreams; +extern int EGong_interface_init(unsigned int requirement_mask); +extern int EGong_interface_cycle(void); +extern void EGong_interface_deinit(void); +extern struct EGong_interface EGong_interfaces[]; +extern int EGong_interface_setup(struct EGong_interface *interface); +extern int EGong_interface_activate(struct EGong_interface *interface); +extern int EGong_interface_shutdown(struct EGong_interface *interface); +extern int EGong_interface_deactivate(struct EGong_interface *interface); +extern struct EGong_interface *EGong_interface_get_from_id(char identifier); + +enum EGONG_INTERFACE_RETURN{ + EGONG_INTERFACE_RETURN_FATAL=-2, + EGONG_INTERFACE_RETURN_ERROR=-1, + EGONG_INTERFACE_RETURN_OK=0, + EGONG_INTERFACE_RETURN_EXIT=1, + EGONG_INTERFACE_RETURN_BREAK=2 +}; diff --git a/include/Interfaces/Audio.h b/include/Interfaces/Audio.h @@ -0,0 +1,6 @@ +#pragma once + + +int EGong_if_audio_setup(struct EGong_interface *interface); +int EGong_if_audio_display(struct EGong_interface *interface, const char *msg); +int EGong_if_audio_shutdown(struct EGong_interface *interface); diff --git a/include/Interfaces/CMD.h b/include/Interfaces/CMD.h @@ -0,0 +1,27 @@ +#pragma once +#include <EGong/Util/Command.h> +#include <EGong/Interfaces.h> + + +enum EGONG_IF_CMD_EXEC{ + EGONG_IF_CMD_SETUP=(1<<0), + EGONG_IF_CMD_CYCLE=(1<<1), + EGONG_IF_CMD_SHUTDOWN=(1<<2) +}; + +struct EGong_command_if_cmd{ + struct EGong_command command; + unsigned int execute; +}; + +extern int EGong_if_cmd_interfaceselect(const char *data); +extern struct EGong_command_if_cmd *EGong_if_cmd_get_from_char(const char *commandline); +extern int EGong_if_cmd_exec(unsigned int execution, struct EGong_interface *interface, char **msg, char **dest); +extern int EGong_if_cmd_setup(struct EGong_interface *interface); +extern int EGong_if_cmd_cycle(struct EGong_interface *interface, char **msg, char **dest); +extern int EGong_if_cmd_shutdown(struct EGong_interface *interface); + +extern int EGong_if_cmd_gtk_msg(void); +extern int EGong_if_cmd_windows_msg(void); +extern int EGong_if_cmd_send_message(char *msg); +extern int EGong_if_cmd_help(void); diff --git a/include/Interfaces/GTK.h b/include/Interfaces/GTK.h @@ -0,0 +1,17 @@ +#pragma once +#include <EGong/Interfaces.h> +#include <gtk/gtk.h> + +extern GtkWidget *Egong_if_gtk_root; +int EGong_if_gtk_int_setup(unsigned int what); + +int EGong_if_gtk_setup(struct EGong_interface *interface); +int EGong_if_gtk_cycle(struct EGong_interface *interface, char **msg, char **dest); +int EGong_if_gtk_display(struct EGong_interface *interface, const char *msg); +int EGong_if_gtk_shutdown(struct EGong_interface *interface); + +enum EGONG_IF_GTK_INIT{ + EGONG_IF_GTK_INIT_ROOT=(1<<0), + EGONG_IF_GTK_INIT_TRAY=(1<<1), + EGONG_IF_GTK_INIT_ALL=(~0) +}; diff --git a/include/Interfaces/GTK/Message.h b/include/Interfaces/GTK/Message.h @@ -0,0 +1,2 @@ +#pragma once +extern void EGong_if_gtk_msg_display(const char *msg); diff --git a/include/Interfaces/GTK/NewMessage.h b/include/Interfaces/GTK/NewMessage.h @@ -0,0 +1,8 @@ +#pragma once +#include <gtk/gtk.h> +extern GtkWidget *EGong_if_gtk_newmsg_dialog; +extern void EGong_if_gtk_newmsg_send_callback(GtkDialog *caller, guint button, gpointer data); + +extern void EGong_if_gtk_newmsg_display_construct(unsigned short int single); +extern void EGong_if_gtk_newmsg_display_single(void); +extern void EGong_if_gtk_newmsg_display(void); diff --git a/include/Interfaces/GTK/TrayIcon.h b/include/Interfaces/GTK/TrayIcon.h @@ -0,0 +1,13 @@ +#pragma once + +#include <gtk/gtk.h> +extern GtkStatusIcon *EGong_if_gtk_tray_root; +extern GtkWidget *EGong_if_gtk_tray_menu; +extern void EGong_if_gtk_tray_popup(GtkStatusIcon *icon, guint button, guint activation_time, gpointer data); +extern int EGong_if_gtk_tray_setup(); + +struct EGong_if_gtk_tray_menu_call{ + char *name; + char *tooltip; + char *message; +}; diff --git a/include/Interfaces/STDIO.h b/include/Interfaces/STDIO.h @@ -0,0 +1,7 @@ +#pragma once +#include <EGong/Interfaces.h> + + +extern int EGong_if_stdio_setup(struct EGong_interface *interface); +extern int EGong_if_stdio_cycle(struct EGong_interface *interface, char **msg, char **dest); +extern int EGong_if_stdio_display(struct EGong_interface *interface, const char *msg); diff --git a/include/Interfaces/Windows.h b/include/Interfaces/Windows.h @@ -0,0 +1,8 @@ +#pragma once + + +extern int EGong_if_win_setup(struct EGong_interface *interface); +extern int EGong_if_win_cycle(struct EGong_interface *interface, char **msg, char **dest); +extern int EGong_if_win_display(struct EGong_interface *interface, const char *msg); + +extern int EGong_if_win_getmsgdialog(); diff --git a/include/Packet.h b/include/Packet.h @@ -0,0 +1,31 @@ +#pragma once +#include <stdint.h> +#include <stddef.h> +#include <openssl/sha.h> +#include <EGong/Util/Socket.h> + + +#define EGONG_PACKET_RAND_LENGTH 10 +#define EGONG_PACKET_HASH_LENGTH SHA256_DIGEST_LENGTH +#define EGONG_PACKET_LENGTH_LENGTH sizeof(((struct EGong_packet*) 0)->message.length) + +#define EGONG_PACKET_MSGHEADLEN EGONG_PACKET_RAND_LENGTH+EGONG_PACKET_HASH_LENGTH+EGONG_PACKET_LENGTH_LENGTH +#define EGONG_PACKET_MSGLEN(MSGSIZE) EGONG_PACKET_MSGHEADLEN+MSGSIZE + +struct EGong_packet{ + char rand[EGONG_PACKET_RAND_LENGTH]; + unsigned char hash[EGONG_PACKET_HASH_LENGTH]; + struct { + uint16_t length; + char *data; + } message; +}; + + +extern int EGong_calculate_package_hash(struct EGong_packet *packet, unsigned char *dest, char *cookie); +extern int EGong_generate_packet(struct EGong_packet *packet, const char *msg, unsigned int msg_length); +extern int EGong_send_packet(struct EGong_packet *packet, const char *dest); +extern void EGong_packet_free(struct EGong_packet *packet); +extern int EGong_packet_alloc(struct EGong_packet *packet, char **dest, unsigned int additional); +extern int EGong_get_packet(SOCKET *sock, struct EGong_packet *packet); +extern int EGong_packet_verify(struct EGong_packet *packet, char *cookie); diff --git a/include/Util/Command.h b/include/Util/Command.h @@ -0,0 +1,44 @@ +#pragma once +#include <stddef.h> +#include <stdint.h> +#include <EGong/Util/Misc.h> +struct EGong_command_type{ + unsigned int type; + unsigned int args; +}; + +enum EGONG_COMMAND_TYPE{ + EGONG_COMMAND_UINT_INC, + EGONG_COMMAND_UINT_DEC, + EGONG_COMMAND_UINT_SET, + EGONG_COMMAND_STR_SET, + EGONG_COMMAND_BOOL_TRUE, + EGONG_COMMAND_BOOL_FALSE, + EGONG_COMMAND_BOOL_SET, + EGONG_COMMAND_FUNC_VOID, + EGONG_COMMAND_FUNC_UINT, + EGONG_COMMAND_FUNC_CHAR, + EGONG_COMMAND_FUNC_2CHAR +}; +enum EGONG_COMMAND_MATCH{ + EGONG_COMMAND_MATCH_SHORT=(1<<0), + EGONG_COMMAND_MATCH_LONG=(1<<0), + EGONG_COMMAND_MATCH_ANY=~0 +}; + +struct EGong_command{ + char *longname; + char *shortname; + char *description; + + struct EGong_command_type type; + void *pointer; +}; + +struct EGong_command_array{ + struct EGong_static_array array; +}; + +extern struct EGong_command *EGong_command_match(struct EGong_command_array *commands, const char *data, unsigned int match_type); +extern int EGong_command_exec(struct EGong_command *command, void **data); +extern void EGong_command_print_help(struct EGong_command_array *commands, int destination, char *appendix); diff --git a/include/Util/Config.h b/include/Util/Config.h @@ -0,0 +1,53 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> +#include <EGong/Util/Config_Compiletime.h> + +struct EGong_config_log{ + unsigned short int level; + unsigned short int color; + unsigned int destinations; +}; +struct EGong_config_packet{ + size_t packet_maxlen; + char *cookie; +}; +struct EGong_config_server{ + unsigned int port; + char *bind_ip; +}; +struct EGong_config{ + struct EGong_config_log log; + struct EGong_config_server server; + struct EGong_config_packet packet; +}; + +struct EGong_config_file_entry{ + char *name; + unsigned short int type; + uintptr_t data_offset; +}; +enum EGONG_CONFIG_FILE_ENTRY{ + EGONG_CONFIG_FILE_LOG_LEVEL, + EGONG_CONFIG_FILE_LOG_COLOR, + EGONG_CONFIG_FILE_LOG_DEST, + EGONG_CONFIG_FILE_PACKET_LEN, + EGONG_CONFIG_FILE_PACKET_COOKIE, + EGONG_CONFIG_FILE_SERVER_PORT, + EGONG_CONFIG_FILE_SERVER_BINDIP, + EGONG_CONFIG_FILE_ENTRYCOUNT, +}; +enum EGONG_CONFIG_FILE_TYPE{ + EGONG_CONFIG_TYPE_STRING, + EGONG_CONFIG_TYPE_UINT, + EGONG_CONFIG_TYPE_BITMASK, + EGONG_CONFIG_TYPE_BOOL, +}; +extern struct EGong_config_file_entry EGong_configuration_file_interface[EGONG_CONFIG_FILE_ENTRYCOUNT]; + +extern struct EGong_config EGong_global_configuration; + +extern void EGong_config_set_defaults(struct EGong_config *conf); +extern void EGong_config_init(struct EGong_config *conf); + diff --git a/include/Util/Config_Compiletime.h b/include/Util/Config_Compiletime.h @@ -0,0 +1,4 @@ +/* #undef USE_GTK */ +/* #undef USE_AO */ +/* #undef USE_WINGUI */ + diff --git a/include/Util/Config_Compiletime.h.in b/include/Util/Config_Compiletime.h.in @@ -0,0 +1,4 @@ +#cmakedefine USE_GTK +#cmakedefine USE_AO +#cmakedefine USE_WINGUI + diff --git a/include/Util/File.h b/include/Util/File.h @@ -0,0 +1 @@ +#pragma once diff --git a/include/Util/Log.h b/include/Util/Log.h @@ -0,0 +1,55 @@ +#pragma once +#define WIDEN2(x) # x +#define WIDEN(x) WIDEN2(x) + +#define LOG_COMPOSE_SRC (const struct log_source){.file={.v=__FILE__, .l=sizeof(__FILE__)}, .line={.v=WIDEN(__LINE__), .l=sizeof(WIDEN(__LINE__))}, .func={.v=__func__, .l=sizeof(__func__)}} + +#include <string.h> +#include <EGong/Util/Config.h> +struct log_source_string{ + const char *v; + unsigned int l; +}; +struct log_source{ + struct log_source_string file; + struct log_source_string line; + struct log_source_string func; +}; +enum LOG_LEVELS{ + LOG_LEVEL_DEBUG, + LOG_LEVEL_INFO, + LOG_LEVEL_WARNING, + LOG_LEVEL_ERROR, + LOG_LEVEL_FATAL, + LOG_LEVEL_COUNT +}; +enum LOG_DESTINATIONS{ + LOG_DEST_STDIO=(1<<0), + LOG_DEST_FILE=(1<<1), + LOG_DEST_GTK=(1<<2) +}; +enum LOG_TYPES{ + LOG_TYPE_NORMAL, + LOG_TYPE_RESULT, + LOG_TYPE_RAW, + LOG_TYPE_SIGNAL + #ifdef _WIN32 + ,LOG_TYPE_SOCKET + #endif +}; +#ifndef _WIN32 + #define LOG_TYPE_SOCKET LOG_TYPE_SIGNAL +#endif +struct log_level{ + const char *name; + char color[10]; +}; + + +extern void do_log_call(const struct log_source src, const char *msg, unsigned int msglength, unsigned int type, unsigned int level, unsigned int destmask); +extern void do_log_call_composite(const struct log_source src, unsigned int type, unsigned int level, unsigned int destmask, ...); +extern struct log_level log_levels[LOG_LEVEL_COUNT]; + +#define do_log(MSG, TYPE, LEVEL) do_log_call(LOG_COMPOSE_SRC,MSG,sizeof(MSG),TYPE,LEVEL,EGong_global_configuration.log.destinations) +#define do_log_comp(TYPE, LEVEL, MSGS) do_log_call_composite(LOG_COMPOSE_SRC,TYPE,LEVEL,EGong_global_configuration.log.destinations, #MSGS, NULL) +#define do_log_dynamic(MSG, TYPE, LEVEL) do_log_call(LOG_COMPOSE_SRC,MSG,strlen(MSG),TYPE,LEVEL,EGong_global_configuration.log.destinations) diff --git a/include/Util/Misc.h b/include/Util/Misc.h @@ -0,0 +1,20 @@ +#pragma once +#include <stddef.h> +#include <unistd.h> +#define CSIZEOF(VAR) (sizeof(VAR))/(sizeof(*(VAR))) + +extern int EGong_global_argc; +extern char **EGong_global_argv; +extern int EGong_misc_get_rand(char *dest, size_t length); + +#define STDNWRITE(str,len) (void)write(STDOUT_FILENO, str, len) +#define STDWRITE(str) STDNWRITE(str,sizeof(str)) +#define STDWRITED(str) STDNWRITE(str,strlen(str)) +#define STRNCAT(dest,str,len) strncpy(dest,str,len); dest+=len; +#define STRCAT(dest,str) STRNCAT(dest,str,sizeof(str)-1) + +struct EGong_static_array{ + void *elements; + ssize_t element_count; + ssize_t element_size; +}; diff --git a/include/Util/Socket.h b/include/Util/Socket.h @@ -0,0 +1,22 @@ +#pragma once + +#include <EGong/Util/Config.h> +#ifdef _WIN32 + #include <winsock2.h> + #define MSG_DONTWAIT 0 + typedef short sa_family_t; +#else + #include <sys/socket.h> + typedef int SOCKET; +#endif +extern SOCKET EGong_listen_sock; + +extern int EGong_sockets_setup(void); +extern int EGong_sockets_shutdown(void); +extern void EGong_socket_close(SOCKET *sock); +extern int EGong_listener_init(SOCKET *sock, struct EGong_config_server *config); +extern int EGong_listener_get(SOCKET *sock, char *dest, int length, struct sockaddr *source, int flags); +extern int EGong_socket_open(SOCKET *sock); +extern int EGong_sendto(SOCKET *sock, const char *dest, const char *msg, size_t msg_len, struct EGong_config_server *config); +extern void EGong_listener_close(SOCKET *sock); +extern int EGong_socket_cmp_ip(SOCKET *sock, struct sockaddr *sockaddr); diff --git a/include/Util/Waiter.h b/include/Util/Waiter.h @@ -0,0 +1,13 @@ +#pragma once + +extern unsigned int EGong_waiter_highest_fd; +extern int EGong_waiter_init(void); +extern int EGong_waiter_add(int sock, unsigned short int type); +extern int EGong_waiter_del(int sock); +extern int EGong_waiter_wait(void); + + +enum EGONG_WAITER_TYPE{ + EGONG_WAITER_FD, + EGONG_WAITER_SOCKET +}; diff --git a/src/CNC.c b/src/CNC.c @@ -0,0 +1,95 @@ +#define WIN32_LEAN_AND_MEAN +#include <EGong/CNC.h> +#include <EGong/Packet.h> +#include <EGong/Util/Socket.h> +#include <EGong/Util/Log.h> +#include <EGong/Util/Waiter.h> +#include <string.h> +#include <unistd.h> +#ifdef EGONG_USE_GTK + #include <EGong/Interfaces/GTK.h> +#endif + + + +unsigned int EGong_cnc_running=0; + +int EGong_cnc_init(unsigned int requirements){ + if((requirements&(EGONG_REQUIREMENT_SOCKETS|EGONG_REQUIREMENT_LISTENER)&~EGong_cnc_running)>0){ + if(EGong_sockets_setup()<0){ + do_log("Couldn't initialize sockets", LOG_TYPE_NORMAL, LOG_LEVEL_FATAL); + return -1; + } + else{ + EGong_cnc_running|=EGONG_REQUIREMENT_SOCKETS; + } + } + if((requirements&EGONG_REQUIREMENT_LISTENER&~EGong_cnc_running)>0){ + if(EGong_listener_init(NULL,NULL)<0){ + do_log("Couldn't initialize listener", LOG_TYPE_NORMAL, LOG_LEVEL_FATAL); + return -1; + } + else{ + EGong_waiter_add(EGong_listen_sock, EGONG_WAITER_SOCKET); + EGong_cnc_running|=EGONG_REQUIREMENT_LISTENER; + } + } + #ifdef EGONG_USE_GTK + if((requirements&EGONG_REQUIREMENT_GTK&~EGong_cnc_running)>0){ + if(EGong_if_gtk_int_setup(EGONG_IF_GTK_INIT_ROOT)<0){ + do_log("Couldn't initialize GTK", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return -2; + } + else{ + EGong_cnc_running|=EGONG_REQUIREMENT_GTK; + } + } + #endif + return 0; +} +int EGong_cnc_sendmessage_broad(const char *msg){ + return EGong_cnc_sendmessage(msg, NULL); +} +int EGong_cnc_sendmessage(const char *msg, const char *dest){ + if(dest==NULL){ + dest="255.255.255.255"; + } + struct EGong_packet packet; + EGong_generate_packet(&packet, msg, strlen(msg)); + if(EGong_send_packet(&packet, dest)<0){ + do_log("Couldn't send packet.", LOG_TYPE_NORMAL, LOG_LEVEL_WARNING); + } + else{ + do_log("Message sent", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + } + return 0; +} + +int EGong_cnc_getmessage(char **msg){ + struct EGong_packet packet; + int ret=EGong_get_packet(NULL, &packet); + if(ret!=0){ + return ret; + } + if(EGong_packet_verify(&packet, NULL)){ + *msg=packet.message.data; + } + else{ + EGong_packet_free(&packet); + do_log("Packet didn't verify.", LOG_TYPE_NORMAL, LOG_LEVEL_INFO); + return -2; + } + return ret; +} +void EGong_cnc_freemessage(char *msg){ + struct EGong_packet virtpack; + virtpack.message.data=msg; + EGong_packet_free(&virtpack); +} + +void EGong_cnc_deinit(void){ + if((EGong_cnc_running&EGONG_REQUIREMENT_LISTENER)>0){ + EGong_listener_close(NULL); + EGong_sockets_shutdown(); + } +} diff --git a/src/EGong b/src/EGong Binary files differ. diff --git a/src/EGong.c b/src/EGong.c @@ -0,0 +1,32 @@ +#include <EGong/Util/Log.h> +#include <EGong/Util/Misc.h> +#include <EGong/Util/Config.h> +#include <EGong/Interfaces.h> +#include <EGong/Util/Waiter.h> +#include <EGong/CNC.h> +#include <EGong/Packet.h> + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> +int main(int argc, char **argv){ + + EGong_config_init(NULL); + EGong_global_argc=argc; + EGong_global_argv=argv; + if(EGong_waiter_init()<0){ + return -1; + } + + if(EGong_interface_init(0)<0){ + return -1; + } + + while(EGong_interface_cycle()==0){ + EGong_waiter_wait(); + } + + EGong_cnc_deinit(); + return 0; +} diff --git a/src/Interfaces.c b/src/Interfaces.c @@ -0,0 +1,263 @@ +#include <EGong/CNC.h> +#include <EGong/Interfaces/STDIO.h> +#include <EGong/Interfaces/CMD.h> +#include <EGong/Util/Config.h> +#ifdef USE_GTK + #include <EGong/Interfaces/GTK.h> +#endif +#ifdef USE_AO + #include <EGong/Interfaces/Audio.h> +#endif +#ifdef USE_WINGUI + #include <EGong/Interfaces/Windows.h> +#endif +#include <EGong/Util/Log.h> +#include <EGong/Util/Misc.h> +#include <stdlib.h> + +struct EGong_interface EGong_interfaces[]={ + { + .name="CMD", + .identifier='C', + .requirements=EGONG_REQUIREMENT_NONE, + .state=EGONG_INTERFACE_ACTIVE, + .setup=&EGong_if_cmd_setup, + .cycle=&EGong_if_cmd_cycle, + .display_message=NULL, + .shutdown=NULL + }, + { + .name="STDIO", + .identifier='S', + .requirements=EGONG_REQUIREMENT_LISTENER|EGONG_REQUIREMENT_TERMINAL, + .state=0, + .setup=&EGong_if_stdio_setup, + .cycle=&EGong_if_stdio_cycle, + .display_message=&EGong_if_stdio_display, + .shutdown=NULL + }, + #ifdef USE_GTK + { + .name="GTK", + .identifier='G', + .requirements=EGONG_REQUIREMENT_LISTENER|EGONG_REQUIREMENT_GTK, + .state=0, + .setup=&EGong_if_gtk_setup, + .cycle=&EGong_if_gtk_cycle, + .display_message=&EGong_if_gtk_display, + .shutdown=&EGong_if_gtk_shutdown + }, + #endif + #ifdef USE_AO + { + .name="Audio", + .identifier='A', + .requirements=EGONG_REQUIREMENT_LISTENER, + .state=0, + .setup=&EGong_if_audio_setup, + .cycle=NULL, + .display_message=&EGong_if_audio_display, + .shutdown=&EGong_if_audio_shutdown + } + #endif + #ifdef USE_WINGUI + { + .name="WinGUI", + .identifier='W', + .requirements=EGONG_REQUIREMENT_LISTENER, + .state=0, + .setup=&EGong_if_win_setup, + .cycle=NULL, + .display_message=NULL, + .shutdown=NULL + } + #endif +}; +unsigned short int EGong_interfaces_global_init_done=0; +unsigned short int EGong_interfaces_userstreams=0; +unsigned int EGong_interfaces_requirements=0; +unsigned int EGong_interfaces_requirement_mask=0; + +unsigned short int EGong_interface_if_count_ustream(struct EGong_interface *interface){ + unsigned short int streams=0; + if(interface->display_message!=NULL){ + streams++; + } + if(interface->cycle!=NULL){ + streams++; + } + return streams; +} +int EGong_interface_setup(struct EGong_interface *interface){ + if((interface->requirements&EGong_interfaces_requirement_mask)>0){ + do_log_call_composite(LOG_COMPOSE_SRC, LOG_TYPE_NORMAL, LOG_LEVEL_ERROR, EGong_global_configuration.log.destinations, "Couldn't setup interface ", interface->name, " due to unmet dependencies", NULL); + } + else{ + if(EGong_cnc_init(interface->requirements&(~EGong_interfaces_requirements))<0){ + do_log("Couldn't get requirements", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return EGONG_INTERFACE_RETURN_ERROR; + } + else{ + EGong_interfaces_requirements|=interface->requirements; + } + } + if(interface->setup!=NULL&&interface->setup(interface)<0){ + do_log_call_composite(LOG_COMPOSE_SRC, LOG_TYPE_NORMAL, LOG_LEVEL_ERROR, EGong_global_configuration.log.destinations, "Couldn't setup interface ", interface->name, NULL); + return EGONG_INTERFACE_RETURN_ERROR; + } + interface->state|=EGONG_INTERFACE_SETUP; + EGong_interfaces_userstreams+=EGong_interface_if_count_ustream(interface); + return 0; +} +int EGong_interface_activate(struct EGong_interface *interface){ + if((interface->state&EGONG_INTERFACE_SETUP)==0&&EGong_interfaces_global_init_done==1){ + if(EGong_interface_setup(interface)<0){ + return -1; + } + } + if((interface->state&EGONG_INTERFACE_ACTIVE)>0){ + return 1; + } + interface->state|=EGONG_INTERFACE_ACTIVE; + EGong_interfaces_userstreams+=EGong_interface_if_count_ustream(interface); + return 0; +} +int EGong_interface_shutdown(struct EGong_interface *interface){ + if((interface->state&EGONG_INTERFACE_SETUP)>0){ + return 1; + } + int ret=0; + if(interface->shutdown(interface)<0){ + do_log_call_composite(LOG_COMPOSE_SRC, LOG_TYPE_NORMAL, LOG_LEVEL_ERROR, EGong_global_configuration.log.destinations, "Couldn't shutdown interface ", interface->name, NULL); + ret=-1; + } + interface->state&=~EGONG_INTERFACE_SETUP; + EGong_interface_deactivate(interface); + return ret; +} +int EGong_interface_deactivate(struct EGong_interface *interface){ + if((interface->state&EGONG_INTERFACE_ACTIVE)==0){ + return 1; + } + interface->state&=~EGONG_INTERFACE_ACTIVE; + EGong_interfaces_userstreams-=EGong_interface_if_count_ustream(interface); + return 0; +} +struct EGong_interface *EGong_interface_get_from_id(char identifier){ + int i; + for(i=0; i<CSIZEOF(EGong_interfaces); i++){ + if(EGong_interfaces[i].identifier==identifier){ + return &EGong_interfaces[i]; + } + } + return NULL; +} +int EGong_interface_interpret_ret(int ret){ + switch(ret){ + case EGONG_INTERFACE_RETURN_FATAL: + do_log("Couldn't run interface function, exiting", LOG_TYPE_NORMAL, LOG_LEVEL_FATAL); + case EGONG_INTERFACE_RETURN_ERROR: + do_log("Couldn't run interface function, skipping", LOG_TYPE_NORMAL, LOG_LEVEL_WARNING); + break; + case EGONG_INTERFACE_RETURN_EXIT: + do_log("Interface function requested exit", LOG_TYPE_NORMAL, LOG_LEVEL_INFO); + break; + case EGONG_INTERFACE_RETURN_BREAK: + do_log("Interface function requested queueabortion", LOG_TYPE_NORMAL, LOG_LEVEL_INFO); + break; + } + return ret; +} +int EGong_interface_init(unsigned int requirement_mask){ + EGong_interfaces_requirement_mask=requirement_mask; + int i, ret; + for(i=0; i<CSIZEOF(EGong_interfaces); i++){ + if((EGong_interfaces[i].state&(EGONG_INTERFACE_ACTIVE))>0&&EGong_interfaces[i].setup!=NULL){ + ret=EGong_interface_interpret_ret(EGong_interface_setup(&EGong_interfaces[i])); + if(ret>EGONG_INTERFACE_RETURN_OK){ + EGong_interfaces[i].state&=~(EGONG_INTERFACE_ACTIVE|EGONG_INTERFACE_SETUP); + } + if(ret==EGONG_INTERFACE_RETURN_FATAL){ + return -1; + } + else if(ret==EGONG_INTERFACE_RETURN_EXIT){ + return 1; + } + else if(ret==EGONG_INTERFACE_RETURN_BREAK){ + break; + } + } + } + if(EGong_interfaces_userstreams==0){ + do_log("No userstreams available", LOG_TYPE_NORMAL, LOG_LEVEL_FATAL); + return -1; + } + EGong_interfaces_global_init_done=1; + do_log("Interfaces initialized", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + return 0; +} +int EGong_interface_cycle(void){ + if(EGong_interfaces_userstreams==0){ + do_log("No userstreams found, exiting...", LOG_TYPE_NORMAL, LOG_LEVEL_INFO); + return 1; + } + int i, ret; + char* msg; + char *dest; + for(i=0; i<CSIZEOF(EGong_interfaces); i++){ + if((EGong_interfaces[i].state&EGONG_INTERFACE_ACTIVE)>0&&EGong_interfaces[i].cycle!=NULL){ + msg=dest=NULL; + ret=EGong_interface_interpret_ret(EGong_interfaces[i].cycle(&EGong_interfaces[i], &msg, &dest)); + if(ret==EGONG_INTERFACE_RETURN_FATAL){ + return -1; + } + else if(ret==EGONG_INTERFACE_RETURN_EXIT){ + return 1; + } + else if(ret==EGONG_INTERFACE_RETURN_BREAK){ + break; + } + else if(msg!=NULL){ + EGong_cnc_sendmessage(msg, NULL); + free(msg); + } + } + } + msg=NULL; + if(((EGong_interfaces_requirements&EGONG_REQUIREMENT_LISTENER)>0)&&EGong_cnc_getmessage(&msg)==0){ + for(i=0; i<CSIZEOF(EGong_interfaces); i++){ + if((EGong_interfaces[i].state&EGONG_INTERFACE_ACTIVE)>0&&EGong_interfaces[i].display_message!=NULL){ + ret=EGong_interface_interpret_ret(EGong_interfaces[i].display_message(&EGong_interfaces[i],msg)); + if(ret==EGONG_INTERFACE_RETURN_FATAL){ + return -1; + } + else if(ret==EGONG_INTERFACE_RETURN_EXIT){ + return 1; + } + else if(ret==EGONG_INTERFACE_RETURN_BREAK){ + break; + } + } + } + } + if(msg!=NULL){ + EGong_cnc_freemessage(msg); + } + return 0; +} + +void EGong_interface_deinit(void){ + EGong_cnc_deinit(); + int i, ret; + for(i=0; i<sizeof(EGong_interfaces)/sizeof(*EGong_interfaces); i++){ + if((EGong_interfaces[i].state&EGONG_INTERFACE_SETUP)>0&&EGong_interfaces[i].shutdown!=NULL){ + ret=EGong_interface_interpret_ret(EGong_interface_shutdown(&EGong_interfaces[i])); + if(ret==EGONG_INTERFACE_RETURN_EXIT){ + return; + } + else if(ret==EGONG_INTERFACE_RETURN_BREAK){ + break; + } + } + } +} diff --git a/src/Interfaces/Audio.c b/src/Interfaces/Audio.c @@ -0,0 +1,62 @@ +#include <ao/ao.h> +#include <EGong/Interfaces.h> +#include <EGong/Util/Log.h> +#include <string.h> +#include <math.h> + + +#define BUFFERSIZE EGong_if_audio_format.bits/8 * EGong_if_audio_format.channels * EGong_if_audio_format.rate + +ao_device *EGong_if_audio_device; +ao_sample_format EGong_if_audio_format; +int EGong_if_audio_driver; +char *EGong_if_audio_buffer; + +int EGong_if_audio_setup(struct EGong_interface *interface){ + ao_initialize(); + do_log("Initialized audio", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + EGong_if_audio_driver = ao_default_driver_id(); + if(EGong_if_audio_driver==-1){ + do_log("Couldn't get default driver ID", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + ao_shutdown(); + return EGONG_INTERFACE_RETURN_ERROR; + } + do_log("Got driver ID", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + + memset(&EGong_if_audio_format, 0, sizeof(EGong_if_audio_format)); + EGong_if_audio_format.bits = 16; + EGong_if_audio_format.channels = 2; + EGong_if_audio_format.rate = 11025; + EGong_if_audio_format.byte_format = AO_FMT_LITTLE; + + EGong_if_audio_device=ao_open_live(EGong_if_audio_driver, &EGong_if_audio_format, NULL); + if(EGong_if_audio_device==NULL){ + do_log("couldn't open device", LOG_TYPE_SIGNAL, LOG_LEVEL_ERROR); + ao_shutdown(); + return EGONG_INTERFACE_RETURN_ERROR; + } + do_log("Opened audio device", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + + EGong_if_audio_buffer = calloc(BUFFERSIZE,sizeof(char)); + + int sample,i; + for (i = 0; i < EGong_if_audio_format.rate; i++) { + sample = (int)(1 * 32768.0 * + sin(2 * M_PI * 440.0 * ((float) i/EGong_if_audio_format.rate))); + EGong_if_audio_buffer[4*i] = EGong_if_audio_buffer[4*i+2] = sample & 0xff; + EGong_if_audio_buffer[4*i+1] = EGong_if_audio_buffer[4*i+3] = (sample >> 8) & 0xff; + } + return EGONG_INTERFACE_RETURN_OK; +} +int EGong_if_audio_display(struct EGong_interface *interface, const char *msg){ + + do_log("Playing Audio", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + ao_play(EGong_if_audio_device, EGong_if_audio_buffer, BUFFERSIZE); + return EGONG_INTERFACE_RETURN_OK; +} + +int EGong_if_audio_shutdown(struct EGong_interface *interface){ + ao_close(EGong_if_audio_device); + ao_shutdown(); + return EGONG_INTERFACE_RETURN_OK; +} diff --git a/src/Interfaces/CMD.c b/src/Interfaces/CMD.c @@ -0,0 +1,181 @@ +#include <EGong/Interfaces.h> +#include <EGong/Interfaces/CMD.h> +#include <EGong/Interfaces.h> +#include <EGong/Util/Log.h> +#include <EGong/Util/Misc.h> +#include <EGong/Util/Command.h> +#include <EGong/Util/Config.h> +#include <stddef.h> +#include <stdint.h> +#ifdef USE_GTK + #include <EGong/Interfaces/GTK/NewMessage.h> +#endif +#ifdef USE_WINGUI + #include <EGong/Interfaces/Windows.h> +#endif +#ifdef _WIN32 + #include <stdio.h> +#endif +int EGong_global_argc; +char **EGong_global_argv; + +struct EGong_command_if_cmd EGong_if_cmd_commands[]={ + { + .command={ + .longname="verbose", + .shortname="v", + .description="Increase verbosity", + .type={.type=EGONG_COMMAND_UINT_DEC, .args=0}, + .pointer=&EGong_global_configuration.log.level + }, + .execute=EGONG_IF_CMD_SETUP + }, + { + .command={ + .longname="quiet", + .shortname="q", + .description="Decrease verbosity", + .type={.type=EGONG_COMMAND_UINT_INC, .args=0}, + .pointer=&EGong_global_configuration.log.level + }, + .execute=EGONG_IF_CMD_SETUP + }, + { + .command={ + .longname="help", + .shortname="h", + .description="Displays the help message", + .type={.type=EGONG_COMMAND_FUNC_VOID, .args=0}, + .pointer=&EGong_if_cmd_help + }, + .execute=EGONG_IF_CMD_SETUP + }, + { + .command={ + .longname="interface", + .shortname="I", + .description="Select an interface", + .type={.type=EGONG_COMMAND_FUNC_CHAR, .args=1}, + .pointer=&EGong_if_cmd_interfaceselect + }, + .execute=EGONG_IF_CMD_SETUP + }, + { + .command={ + .longname="send-message", + .shortname="s", + .description="Sends a message", + .type={.type=EGONG_COMMAND_FUNC_CHAR, .args=1}, + .pointer=&EGong_if_cmd_send_message + }, + .execute=EGONG_IF_CMD_CYCLE + }, + #ifdef USE_GTK + { + .command={ + .longname="gtk-message", + .shortname="g", + .description="Opens the GTK-Message dialog", + .type={.type=EGONG_COMMAND_FUNC_VOID, .args=0}, + .pointer=&EGong_if_cmd_gtk_msg + }, + .execute=EGONG_IF_CMD_CYCLE + }, + #endif + #ifdef USE_WINGUI + { + .command={ + .longname="windows-message", + .shortname="w", + .description="Opens the Windows-Message dialog", + .type={.type=EGONG_COMMAND_FUNC_VOID, .args=0}, + .pointer=&EGong_if_cmd_windows_msg + }, + .execute=EGONG_IF_CMD_CYCLE + }, + #endif +}; +struct EGong_command_array EGong_if_cmd_commandarray={.array={ + .elements=&EGong_if_cmd_commands, + .element_size=sizeof(*EGong_if_cmd_commands), + .element_count=CSIZEOF(EGong_if_cmd_commands), +}}; + +#ifdef USE_GTK +int EGong_if_cmd_gtk_msg(void){ + EGong_cnc_init(EGONG_REQUIREMENT_GTK); + EGong_if_gtk_newmsg_display_single(); + gtk_main(); + return EGONG_INTERFACE_RETURN_OK; +} +#endif +#ifdef USE_WINGUI +int EGong_if_cmd_windows_msg(void){ + EGong_cnc_init(EGONG_REQUIREMENT_SOCKETS); + EGong_if_win_getmsgdialog(); + return EGONG_INTERFACE_RETURN_OK; +} +#endif +int EGong_if_cmd_send_message(char *msg){ + EGong_cnc_init(EGONG_REQUIREMENT_SOCKETS); + EGong_cnc_sendmessage_broad(msg); + return EGONG_INTERFACE_RETURN_OK; +} +int EGong_if_cmd_help(void){ + STDWRITE("Usage: "); + STDWRITED(EGong_global_argv[0]); + STDWRITE("\n"); + EGong_command_print_help(&EGong_if_cmd_commandarray, STDOUT_FILENO, "\t"); + return EGONG_INTERFACE_RETURN_OK; +} +int EGong_if_cmd_interfaceselect(const char *data){ + struct EGong_interface *interface; + + interface=EGong_interface_get_from_id(data[0]); + if(interface==NULL){ + do_log("Malformed interface specified", LOG_TYPE_NORMAL, LOG_LEVEL_WARNING); + return -EGONG_INTERFACE_RETURN_ERROR; + } + EGong_interface_activate(interface); + return EGONG_INTERFACE_RETURN_OK; +} + +struct EGong_command_if_cmd *EGong_if_cmd_get_from_char(const char *commandline){ + const char *valptr=commandline; + while(*++valptr=='-'); + return (struct EGong_command_if_cmd *)EGong_command_match(&EGong_if_cmd_commandarray,valptr,EGONG_COMMAND_MATCH_ANY); +} +int EGong_if_cmd_exec(unsigned int execution, struct EGong_interface *interface, char **msg, char **dest){ + int i; + char *arg; + struct EGong_command_if_cmd *command=NULL; + for(i=1; i<EGong_global_argc; i++){ + arg=EGong_global_argv[i]; + command=EGong_if_cmd_get_from_char(arg); + if(command==NULL){ + do_log_call_composite(LOG_COMPOSE_SRC, LOG_TYPE_NORMAL, LOG_LEVEL_WARNING, EGong_global_configuration.log.destinations, "Command \"", arg, "\" not found", NULL); + continue; + } + if((command->execute&execution)>0){ + EGong_command_exec((struct EGong_command *)command, (void **)&EGong_global_argv[i+1]); + } + i+=command->command.type.args; + command=NULL; + } + return EGONG_INTERFACE_RETURN_OK; +} +int EGong_if_cmd_setup(struct EGong_interface *interface){ + EGong_if_cmd_exec(EGONG_IF_CMD_SETUP, interface, NULL, NULL); + return EGONG_INTERFACE_RETURN_OK; +} + +int EGong_if_cmd_cycle(struct EGong_interface *interface, char **msg, char **dest){ + EGong_if_cmd_exec(EGONG_IF_CMD_CYCLE, interface, NULL, NULL); + EGong_interface_deactivate(interface); + return EGONG_INTERFACE_RETURN_OK; +} + +int EGong_if_cmd_shutdown(struct EGong_interface *interface){ + EGong_if_cmd_exec(EGONG_IF_CMD_SHUTDOWN, interface, NULL, NULL); + return EGONG_INTERFACE_RETURN_OK; +} diff --git a/src/Interfaces/GTK.c b/src/Interfaces/GTK.c @@ -0,0 +1,57 @@ +#include <EGong/Interfaces/GTK/TrayIcon.h> +#include <EGong/Interfaces/GTK/Message.h> +#include <EGong/Interfaces/GTK.h> +#include <EGong/Interfaces.h> +#include <EGong/Util/Misc.h> +#include <EGong/Util/Log.h> +#include <EGong/Interfaces.h> +#include <gtk/gtk.h> + +GtkWidget *Egong_if_gtk_root; + +unsigned int EGong_if_gtk_initialized; +int EGong_if_gtk_int_setup(unsigned int what){ + gtk_init(&EGong_global_argc, &EGong_global_argv); + if((what&EGONG_IF_GTK_INIT_ROOT&~EGong_if_gtk_initialized)>0){ + Egong_if_gtk_root=gtk_window_new(GTK_WINDOW_TOPLEVEL); + if(Egong_if_gtk_root!=NULL){ + EGong_if_gtk_initialized|=EGONG_IF_GTK_INIT_ROOT; + } + else{ + do_log("Couldn't initialize rootwindow", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return -1; + } + } + if((what&EGONG_IF_GTK_INIT_TRAY&~EGong_if_gtk_initialized)>0){ + if(EGong_if_gtk_tray_setup()<0){ + do_log("Couldn't initialize tray", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return -2; + } + else{ + EGong_if_gtk_initialized|=EGONG_IF_GTK_INIT_TRAY; + } + } + return 0; +} +int EGong_if_gtk_setup(struct EGong_interface *interface){ + if(EGong_if_gtk_int_setup(EGONG_IF_GTK_INIT_ALL)<0){ + return EGONG_INTERFACE_RETURN_ERROR; + } + return 0; +} +int EGong_if_gtk_cycle(struct EGong_interface *interface, char **msg, char **dest){ + interface->cycle=NULL; //Prevent any further execution + EGong_interfaces_userstreams--; //GTK takes over the job of cycling the interfaces. + gtk_main(); + return EGONG_INTERFACE_RETURN_EXIT; +} + +int EGong_if_gtk_display(struct EGong_interface *interface, const char *msg){ + EGong_if_gtk_msg_display(msg); //Shouldn't acutally be used anyway... + return EGONG_INTERFACE_RETURN_OK; +} + +int EGong_if_gtk_shutdown(struct EGong_interface *interface){ + gtk_main_quit(); + return EGONG_INTERFACE_RETURN_OK; +} diff --git a/src/Interfaces/GTK/Message.c b/src/Interfaces/GTK/Message.c @@ -0,0 +1,19 @@ +#include <EGong/Interfaces/GTK/Message.h> +#include <EGong/Interfaces/GTK.h> +#include <gtk/gtk.h> + +void EGong_if_gtk_msg_display(const char *msg){ + GtkWidget *dialog = gtk_dialog_new_with_buttons("Nachricht", + GTK_WINDOW(Egong_if_gtk_root), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + NULL); + GtkWidget *Message; + GtkWidget *content_area=gtk_dialog_get_content_area(GTK_DIALOG (dialog)); + Message=gtk_label_new(msg); + gtk_container_add (GTK_CONTAINER (content_area), Message); + g_signal_connect_swapped(dialog, "response", G_CALLBACK (gtk_widget_destroy), (gpointer)dialog); + + gtk_widget_show_all(dialog); +} diff --git a/src/Interfaces/GTK/NewMessage.c b/src/Interfaces/GTK/NewMessage.c @@ -0,0 +1,47 @@ +#include <gtk/gtk.h> +#include <EGong/Util/Log.h> +#include <EGong/Interfaces/GTK/NewMessage.h> +#include <EGong/Interfaces/GTK/TrayIcon.h> +#include <EGong/Interfaces/GTK.h> +GtkWidget *EGong_if_gtk_newmsg_dialog; +void EGong_if_gtk_newmsg_send_callback(GtkDialog *caller, guint button, gpointer data){ + if(button==GTK_RESPONSE_OK){ + char *message=(char *)gtk_entry_get_text((GtkEntry *)data); + if(message[0]!='\0'){ + EGong_cnc_sendmessage(message,NULL); + } + } + EGong_if_gtk_newmsg_dialog=NULL; + gtk_widget_destroy(GTK_WIDGET(caller)); +} + +void EGong_if_gtk_newmsg_display_construct(unsigned short int single){ + if(EGong_if_gtk_newmsg_dialog==NULL){ + EGong_if_gtk_newmsg_dialog = gtk_dialog_new_with_buttons("Nachricht senden", + GTK_WINDOW(Egong_if_gtk_root), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + NULL); + GtkWidget *Message; + GtkWidget *content_area=gtk_dialog_get_content_area(GTK_DIALOG (EGong_if_gtk_newmsg_dialog)); + Message=gtk_entry_new(); + gtk_container_add (GTK_CONTAINER (content_area), Message); + if(single==1){ + g_signal_connect(EGong_if_gtk_newmsg_dialog, "response", G_CALLBACK (gtk_main_quit), NULL); + } + g_signal_connect(EGong_if_gtk_newmsg_dialog, "response", G_CALLBACK (EGong_if_gtk_newmsg_send_callback), (gpointer)Message); + + } + gtk_widget_show_all(EGong_if_gtk_newmsg_dialog); + +} +void EGong_if_gtk_newmsg_display_single(void){ + EGong_if_gtk_newmsg_display_construct(1); +} +void EGong_if_gtk_newmsg_display(void){ + EGong_if_gtk_newmsg_display_construct(0); +} + diff --git a/src/Interfaces/GTK/TrayIcon.c b/src/Interfaces/GTK/TrayIcon.c @@ -0,0 +1,51 @@ +#include <gtk/gtk.h> +#include <EGong/Interfaces/GTK/TrayIcon.h> +#include <EGong/Interfaces/GTK/NewMessage.h> +#include <EGong/Util/Log.h> +#include <EGong/Util/Misc.h> +#include <EGong/CNC.h> + +GtkStatusIcon *EGong_if_gtk_tray_root; +GtkWidget *EGong_if_gtk_tray_menu; + +struct EGong_if_gtk_tray_menu_call EGong_if_gtk_tray_menu_calls[]={ + {.name="Essen", .tooltip="Zum Essen rufen", .message="Essen!"}, +}; + +void EGong_if_gtk_tray_popup(GtkStatusIcon *icon, guint button, guint activation_time, gpointer data){ + gtk_menu_popup(GTK_MENU(EGong_if_gtk_tray_menu),NULL,NULL,gtk_status_icon_position_menu, icon, button, activation_time); +} +void EGong_if_gtk_tray_predef_call(GtkMenuItem *icon, const char *message){ + EGong_cnc_sendmessage_broad(message); +} +int EGong_if_gtk_tray_setup(){ + EGong_if_gtk_tray_root=gtk_status_icon_new_from_stock(GTK_STOCK_NETWORK); + g_signal_connect(GTK_STATUS_ICON(EGong_if_gtk_tray_root), "activate", G_CALLBACK(EGong_if_gtk_newmsg_display), NULL); + g_signal_connect(GTK_STATUS_ICON(EGong_if_gtk_tray_root), "popup-menu", G_CALLBACK(EGong_if_gtk_tray_popup), NULL); + + EGong_if_gtk_tray_menu=gtk_menu_new(); + + GtkWidget *Exit=gtk_image_menu_item_new_with_label("Exit"); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(Exit),gtk_image_new_from_icon_name(GTK_STOCK_QUIT,GTK_ICON_SIZE_MENU)); + g_signal_connect(G_OBJECT(Exit), "activate", G_CALLBACK(gtk_main_quit), NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(EGong_if_gtk_tray_menu), Exit); + + GtkWidget *predef=gtk_menu_item_new_with_label("Rufen"); + GtkWidget *predefM=gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(predef), predefM); + gtk_menu_shell_prepend(GTK_MENU_SHELL(EGong_if_gtk_tray_menu), predef); + int i; + GtkWidget *callitem; + struct EGong_if_gtk_tray_menu_call *call; + for(i=0; i<CSIZEOF(EGong_if_gtk_tray_menu_calls); i++){ + call=&EGong_if_gtk_tray_menu_calls[i]; + callitem=gtk_menu_item_new_with_label(call->name); + gtk_widget_set_tooltip_text(callitem,call->tooltip); + g_signal_connect(G_OBJECT(callitem), "activate", G_CALLBACK(EGong_if_gtk_tray_predef_call), call->message); + gtk_menu_shell_prepend(GTK_MENU_SHELL(predefM), callitem); + } + + gtk_widget_show_all(EGong_if_gtk_tray_menu); + do_log("Tray initialized", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + return 0; +} diff --git a/src/Interfaces/STDIO.c b/src/Interfaces/STDIO.c @@ -0,0 +1,76 @@ +#include <EGong/Interfaces.h> +#include <EGong/Interfaces/CMD.h> +#include <EGong/Util/Log.h> +#include <EGong/Util/Waiter.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> + +#ifdef _WIN32 + #include <stdio.h> +#else + #include <fcntl.h> +#endif + +int EGong_if_stdio_setup(struct EGong_interface *interface){ + #ifdef _WIN32 + #else + int flags; + flags = fcntl(STDIN_FILENO, F_GETFL); + flags = fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); + #endif + if(EGong_waiter_add(STDIN_FILENO, EGONG_WAITER_FD)<0){ + return EGONG_INTERFACE_RETURN_ERROR; + } + return EGONG_INTERFACE_RETURN_OK; +} + +int EGong_if_stdio_cmd(char *msg){ + const char *data[5]; + unsigned int i=0,arg=0; + while(msg[i]!='\0'){ + if(msg[i]==' '){ + msg[i]='\0'; + data[arg]=&msg[i+1]; + arg++; + } + i++; + } + struct EGong_command_if_cmd *cmd=EGong_if_cmd_get_from_char(msg); + if(cmd==NULL){ + write(STDOUT_FILENO, "Command unknown\n", sizeof("Command unknown\n")); + } + else{ + EGong_command_exec((struct EGong_command *) cmd, (void **)data); + } + return EGONG_INTERFACE_RETURN_OK; +} + +int EGong_if_stdio_cycle(struct EGong_interface *interface, char **msg, char **dest){ + char buffer[50]; + int ret=read(STDIN_FILENO, buffer, 50); + #ifdef _WIN32 + if(ret<0&&errno!=EAGAIN){ + #else + if(ret<0&&errno!=EAGAIN&&errno!=EWOULDBLOCK){ + #endif + return EGONG_INTERFACE_RETURN_ERROR; + } + else if(ret>0){ + buffer[ret-1]='\0'; + if(buffer[0]=='/'){ + EGong_if_stdio_cmd(&buffer[1]); + } + else{ + buffer[ret]='\0'; + *msg=malloc(ret); + strncpy(*msg,buffer, ret); + } + } + return EGONG_INTERFACE_RETURN_OK; +} +int EGong_if_stdio_display(struct EGong_interface *interface, const char *msg){ + write(STDOUT_FILENO,msg,strlen(msg)); + write(STDOUT_FILENO, "\n", sizeof("\n")); + return EGONG_INTERFACE_RETURN_OK; +} diff --git a/src/Interfaces/Windows.c b/src/Interfaces/Windows.c @@ -0,0 +1,91 @@ +#include <EGong/Interfaces.h> +#include <EGong/Interfaces/Windows.h> +#include <EGong/CNC.h> +#include <EGong/Util/Log.h> +#define UNICODE +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +WNDCLASSW EGong_if_win_getmsg = {0}; +HWND EGong_if_win_getmsg_editfield; +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ + HWND hwndButton; + (void) hwndButton; + switch(msg){ + case WM_CREATE: + + EGong_if_win_getmsg_editfield = CreateWindowW(L"Edit", NULL, + WS_CHILD | WS_VISIBLE | WS_BORDER, + 50, 50, 150, 20, hwnd, (HMENU) 0, + NULL, NULL); + + hwndButton = CreateWindowW(L"button", L"Senden", + WS_VISIBLE | WS_CHILD, 50, 100, 80, 25, + hwnd, (HMENU) 1, NULL, NULL); + + break; + + case WM_COMMAND: + + if (HIWORD(wParam) == BN_CLICKED) { + int len = GetWindowTextLengthW(EGong_if_win_getmsg_editfield) + 1; + char text[len]; + char msg[len]; + + GetWindowTextW(EGong_if_win_getmsg_editfield, text, 5+len); + wcstombs(msg,text, len); + + msg[len]='\0'; + EGong_cnc_sendmessage_broad(msg); + PostQuitMessage(0); + } + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + } + return DefWindowProcW(hwnd, msg, wParam, lParam); +} +int EGong_if_win_getmsgdialog(){ + HINSTANCE hInstance = (HINSTANCE)GetWindowLong( GetForegroundWindow(), GWL_HINSTANCE ); + MSG msg; + EGong_if_win_getmsg.lpszClassName = L"EGong Message"; + EGong_if_win_getmsg.hInstance = hInstance; + EGong_if_win_getmsg.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + EGong_if_win_getmsg.lpfnWndProc = WndProc; + EGong_if_win_getmsg.hCursor = LoadCursor(0,IDC_ARROW); + RegisterClassW(&EGong_if_win_getmsg); + + CreateWindowW(EGong_if_win_getmsg.lpszClassName, L"EGong Message", + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 220, 220, 280, 200, 0, 0, hInstance, 0); + while(GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} + +void EGong_if_win_react(){ + do_log("Windowsinterface is a stub", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); +} +int EGong_if_win_setup(struct EGong_interface *interface){ + EGong_if_win_react(); + return EGONG_INTERFACE_RETURN_ERROR; +} + +int EGong_if_win_cmd(char *msg){ + EGong_if_win_react(); + return EGONG_INTERFACE_RETURN_ERROR; +} + +int EGong_if_win_cycle(struct EGong_interface *interface, char **msg, char **dest){ + EGong_if_win_react(); + return EGONG_INTERFACE_RETURN_ERROR; +} + +int EGong_if_win_display(struct EGong_interface *interface, const char *msg){ + EGong_if_win_react(); + return EGONG_INTERFACE_RETURN_ERROR; +} diff --git a/src/Packet.c b/src/Packet.c @@ -0,0 +1,160 @@ +#include <openssl/sha.h> +#include <EGong/Packet.h> +#include <EGong/Util/Socket.h> +#include <EGong/Util/Log.h> +#include <EGong/Util/Misc.h> + +#include <unistd.h> +#include <stdlib.h> + +#include <string.h> +#include <stddef.h> +#ifdef _WIN32 + #include <winsock2.h> +#else + #include <arpa/inet.h> +#endif + +unsigned char EGong_packet_last_hash[EGONG_PACKET_HASH_LENGTH]; +int EGong_calculate_package_hash(struct EGong_packet *packet, unsigned char *dest, char *cookie){ + if(cookie==NULL) + cookie=EGong_global_configuration.packet.cookie; + SHA256_CTX sha256; + SHA256_Init(&sha256); + + SHA256_Update(&sha256, packet->message.data, packet->message.length); + SHA256_Update(&sha256, packet->rand, EGONG_PACKET_RAND_LENGTH); + SHA256_Update(&sha256, cookie, strlen(cookie)); + + SHA256_Final(dest, &sha256); + return 0; +} + +int EGong_generate_packet(struct EGong_packet *packet, const char *msg, unsigned int msg_length){ + EGong_misc_get_rand(packet->rand,EGONG_PACKET_RAND_LENGTH); + + packet->message.length=msg_length; + packet->message.data=(char *)msg; + + EGong_calculate_package_hash(packet,packet->hash, NULL); + + return 0; +} +void EGong_packetbuffer_advance(char **buf, const char *src, size_t length){ + memcpy(*buf, src, length); + *buf+=length; +} +int EGong_send_packet(struct EGong_packet *packet, const char *dest){ + if(packet->message.length==0){ + do_log("Packetsize 0, not sending...", LOG_TYPE_NORMAL, LOG_LEVEL_WARNING); + return -1; + } + SOCKET sock; + if(EGong_socket_open(&sock)<0){ + do_log("Couldn't open socket",LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return -1; + } + #ifdef _WIN32 + char + #else + int + #endif + broadcastEnable=1; + if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable))<0){ + do_log("Couldn't set socket broadcasting",LOG_TYPE_SOCKET, LOG_LEVEL_WARNING); + } + + size_t bufsize=EGONG_PACKET_MSGLEN(packet->message.length); + char *buf=malloc(bufsize); + char *bufptr=buf; + if(buf==NULL){ + do_log("Couldn't allocate buffer",LOG_TYPE_SIGNAL, LOG_LEVEL_ERROR); + return -2; + } + memset(bufptr, 0, bufsize); + memcpy(EGong_packet_last_hash, packet->hash, EGONG_PACKET_HASH_LENGTH); + + EGong_packetbuffer_advance(&bufptr, (const char *)packet->rand, EGONG_PACKET_RAND_LENGTH); + EGong_packetbuffer_advance(&bufptr, (const char *)packet->hash, EGONG_PACKET_HASH_LENGTH); + *(uint16_t *) bufptr=htons(packet->message.length); + bufptr+=EGONG_PACKET_LENGTH_LENGTH; + EGong_packetbuffer_advance(&bufptr, packet->message.data, packet->message.length); + + if(EGong_sendto(&sock, dest, buf, bufsize, NULL)<0){ + do_log("Couldn't send packet body", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return -3; + } + free(buf); + EGong_socket_close(&sock); + return 0; +} + +void EGong_packet_free(struct EGong_packet *packet){ + free(packet->message.data-(EGONG_PACKET_MSGHEADLEN)); +} +int EGong_packetbuf_alloc(size_t size, char **dest, unsigned int additional){ + if(size==0){ + do_log("Tried to allocate message of size 0", LOG_TYPE_NORMAL, LOG_LEVEL_WARNING); + return -1; + } + if(size>EGong_global_configuration.packet.packet_maxlen){ + do_log("Messagesize larger than allowed!", LOG_TYPE_NORMAL, LOG_LEVEL_WARNING); + return -2; + } + *dest=malloc(EGONG_PACKET_MSGLEN(size)+additional); + if(*dest==NULL){ + do_log("Couldn't allocate packet!", LOG_TYPE_SIGNAL, LOG_LEVEL_WARNING); + return -3; + } + return 0; +} + +int EGong_packet_verify(struct EGong_packet *packet, char *cookie){ + unsigned char hash[EGONG_PACKET_HASH_LENGTH]; + EGong_calculate_package_hash(packet, hash, cookie); + return memcmp(packet->hash,hash,EGONG_PACKET_HASH_LENGTH)==0; +} +void EGong_packetbuffer_to_packet(const char *buf, struct EGong_packet *packet){ + memcpy(packet->rand, buf, EGONG_PACKET_RAND_LENGTH); + buf+=EGONG_PACKET_RAND_LENGTH; + memcpy(packet->hash, buf, EGONG_PACKET_HASH_LENGTH); + buf+=EGONG_PACKET_HASH_LENGTH; + packet->message.length=ntohs(*(uint16_t *)buf); + buf+=EGONG_PACKET_LENGTH_LENGTH; + packet->message.data=(char *)buf; +} +void EGong_drop_packet(SOCKET *sock){ + do_log("Dropping packet.", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + EGong_listener_get(sock,NULL,0, NULL, 0); +} +int EGong_get_packet(SOCKET *sock, struct EGong_packet *packet){ + if(sock==NULL){ + sock=&EGong_listen_sock; + } struct sockaddr source; + char packetbuf[EGONG_PACKET_MSGHEADLEN]; + int ret=EGong_listener_get(sock,(char *)packetbuf,EGONG_PACKET_MSGHEADLEN, &source, MSG_PEEK|MSG_DONTWAIT); + if(ret<0){ + do_log("Couldn't receive packet!", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return -1; + } + else if(ret==0){ + do_log("No packet available", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + return 1; + } + else if(0&&memcmp(EGong_packet_last_hash, packetbuf+EGONG_PACKET_RAND_LENGTH, EGONG_PACKET_HASH_LENGTH)==0){ + do_log("Is own packet, dropping", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + EGong_drop_packet(sock); + return 2; + } + uint16_t rawsize=*(uint16_t*)(packetbuf+EGONG_PACKET_RAND_LENGTH+EGONG_PACKET_HASH_LENGTH); + size_t size=ntohs(rawsize); + char *dest; + if(EGong_packetbuf_alloc(size+EGONG_PACKET_MSGHEADLEN,&dest, 1)<0){ + do_log("Couldn't allocate packetbuffer",LOG_TYPE_NORMAL, LOG_LEVEL_WARNING); + EGong_drop_packet(sock); + return -2; + } + ret=EGong_listener_get(sock, dest, EGONG_PACKET_MSGLEN(size), NULL, 0); + EGong_packetbuffer_to_packet(dest,packet); + return 0; +} diff --git a/src/Util/Command.c b/src/Util/Command.c @@ -0,0 +1,72 @@ +#include <EGong/Util/Command.h> +#include <EGong/Util/Log.h> +#include <EGong/Util/Misc.h> +#include <EGong/Interfaces/CMD.h> +#include <stdint.h> +#include <stdio.h> + +struct EGong_command *EGong_command_match(struct EGong_command_array *commands, const char *data, unsigned int match_type){ + unsigned int i; + struct EGong_command *command=NULL; + for(i=0; i<commands->array.element_count; i++){ + command=(commands->array.elements+(uintptr_t)(commands->array.element_size*i)); + if((match_type&EGONG_COMMAND_MATCH_SHORT) && strcmp(command->shortname, data)==0){ + break; + } + if((match_type&EGONG_COMMAND_MATCH_LONG) && strcmp(command->longname, data)==0){ + break; + } + command=NULL; + } + return command; +} +void EGong_command_print_help(struct EGong_command_array *commands, int destination, char *appendix){ + unsigned int i; + size_t appendixlength=strlen(appendix); + struct EGong_command *cmd; + for(i=0; i<commands->array.element_count; i++){ + cmd=(struct EGong_command *)((intptr_t)commands->array.elements+(intptr_t)(commands->array.element_size*i)); + write(destination, appendix, appendixlength); + write(destination, "-", sizeof("-")); + write(destination, cmd->shortname, strlen(cmd->shortname)); + write(destination, "/--", sizeof("/--")); + write(destination, cmd->longname, strlen(cmd->longname)); + write(destination, ": ", sizeof(": ")); + write(destination, cmd->description, strlen(cmd->description)); + write(destination,"\n", sizeof("\n")); + } +} +int EGong_command_exec(struct EGong_command *command, void **data){ + switch(command->type.type){ + case EGONG_COMMAND_BOOL_FALSE: + *(unsigned int *)command->pointer=0; + break; + case EGONG_COMMAND_BOOL_TRUE: + *(unsigned int *)command->pointer=1; + break; + case EGONG_COMMAND_BOOL_SET: + *(unsigned int *)command->pointer=(**(char **)data=='1') ? 1 : 0; + break; + case EGONG_COMMAND_UINT_INC: + if(*(unsigned int *)command->pointer<=(unsigned int)-1) + (*(unsigned int *)command->pointer)++; + break; + case EGONG_COMMAND_UINT_DEC: + if(*(unsigned int *)command->pointer>(unsigned int)0) + (*(unsigned int *)command->pointer)--; + break; + case EGONG_COMMAND_FUNC_VOID: + ((int(*)(void))command->pointer)(); + break; + case EGONG_COMMAND_FUNC_CHAR: + ((int(*)(char *))command->pointer)(*(char **)data); + break; + case EGONG_COMMAND_FUNC_2CHAR: + ((int(*)(char *, char *))command->pointer)(((char **)data)[0],((char **)data)[1]); + break; + default: + do_log("Unknown command type", LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return -1; + } + return 0; +} diff --git a/src/Util/Config.c b/src/Util/Config.c @@ -0,0 +1,68 @@ +#include <EGong/Util/Config.h> +#include <EGong/Util/Log.h> +#include <stdlib.h> + +struct EGong_config EGong_global_configuration; + +struct EGong_config_file_entry EGong_configuration_file_interface[EGONG_CONFIG_FILE_ENTRYCOUNT]={ + [EGONG_CONFIG_FILE_LOG_COLOR]={ + .type=EGONG_CONFIG_TYPE_BOOL, + .name="STDIO-Farben", + .data_offset=offsetof(struct EGong_config,log.color) + }, + [EGONG_CONFIG_FILE_LOG_LEVEL]={ + .type=EGONG_CONFIG_TYPE_UINT, + .name="Log-Level", + .data_offset=offsetof(struct EGong_config,log.level) + }, + [EGONG_CONFIG_FILE_LOG_DEST]={ + .type=EGONG_CONFIG_TYPE_BITMASK, + .name="Logdestinationsbitmaske", + .data_offset=offsetof(struct EGong_config,log.level) + }, + [EGONG_CONFIG_FILE_PACKET_COOKIE]={ + .type=EGONG_CONFIG_TYPE_STRING, + .name="Cookie", + .data_offset=offsetof(struct EGong_config,packet.cookie) + }, + [EGONG_CONFIG_FILE_PACKET_LEN]={ + .type=EGONG_CONFIG_TYPE_STRING, + .name="Packet-Maximallänge", + .data_offset=offsetof(struct EGong_config,log.level) + }, + [EGONG_CONFIG_FILE_SERVER_BINDIP]={ + .type=EGONG_CONFIG_TYPE_STRING, + .name="Bind-IP", + .data_offset=offsetof(struct EGong_config,server.bind_ip) + }, + [EGONG_CONFIG_FILE_SERVER_PORT]={ + .type=EGONG_CONFIG_TYPE_STRING, + .name="Port", + .data_offset=offsetof(struct EGong_config,server.port) + } +}; +void EGong_config_set_defaults(struct EGong_config *conf){ + conf->log.color=0; + conf->log.level=LOG_LEVEL_DEBUG; + conf->log.destinations=LOG_DEST_STDIO; + + conf->server.port=4242; + conf->server.bind_ip="0.0.0.0"; + + conf->packet.packet_maxlen=1000; + conf->packet.cookie="Derpaherp"; +} + +int EGong_config_write(struct EGong_config *conf, int file){ + unsigned int i; + for(i=0;i<EGONG_CONFIG_FILE_ENTRYCOUNT; i++){ + + } + return 0; +} + +void EGong_config_init(struct EGong_config *conf){ + if(conf==NULL) + conf=&EGong_global_configuration; + EGong_config_set_defaults(conf); +} diff --git a/src/Util/File.c b/src/Util/File.c @@ -0,0 +1,25 @@ + +int EGong_file_open(char *path, ...vargs){ + int sock=open(path,vargs); + if(sock<0){ + do_log_call_composite(LOG_COMPOSE_SRC, LOG_TYPE_SIGNAL, LOG_LEVEL_ERROR, "Couldn't open file \"", path, "\"", NULL); + } + return sock; +} + +int FileExists(const TCHAR *fileName){ + #ifdef _WIN32 + DWORD fileAttr; + fileAttr = GetFileAttributes(fileName); + if(fileAttr==0xFFFFFFFF) + return 0; + #else + if(access("file", F_OK)!=0) + return 0; + #endif + return 1; +} + +void EGong_file_close(int file){ + close(file); +} diff --git a/src/Util/Log.c b/src/Util/Log.c @@ -0,0 +1,128 @@ +/* + * SIGI - Swisscom Internet GTK Interface + * + * @author: Dominik Schmidt <domischmidt@swissonline.ch> + * @license: CC-BY-SA-3.0 + * @version: 2.0.0 +*/ +#include <EGong/Util/Log.h> +#include <EGong/Util/Misc.h> + +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#ifdef _WIN32 + #include <stdio.h> + #include <windows.h> + #include <winnt.h> +#endif + +struct log_level log_levels[LOG_LEVEL_COUNT]={ + [LOG_LEVEL_DEBUG]={.name="DEBUG", .color="\e[2;37;40m"}, + [LOG_LEVEL_INFO]={.name="INFO", .color="\e[0;37;40m"}, + [LOG_LEVEL_WARNING]={.name="WARNING", .color="\e[1;33;40m"}, + [LOG_LEVEL_ERROR]={.name="ERROR", .color="\e[1;31;40m"}, + [LOG_LEVEL_FATAL]={.name="FATAL", .color="\e[1;33;41m"} +}; + +void log_write_stdio(const char *msg, unsigned int length, unsigned int type, unsigned int level){ + int fd=STDOUT_FILENO; + if(level>=LOG_LEVEL_WARNING){ + fd=STDERR_FILENO; + } + if(EGong_global_configuration.log.color){ + STDNWRITE(log_levels[level].color,sizeof(((struct log_level *)NULL)->color)); + } + write(fd,msg,length); + if(EGong_global_configuration.log.color){ + STDWRITE("\e[0m"); + } +} +void do_log_call_composite(const struct log_source src, unsigned int type, unsigned int level, unsigned int destmask, ...){ + va_list ap; + va_start(ap, destmask); + char *arg=NULL; + char *buf=NULL; + char *bufptr=buf; + unsigned int length=0, totallength=0, alloc=0; + while(1){ + arg=va_arg(ap, char *); + if(arg==NULL){ + break; + } + length=strlen(arg); + if(length+totallength>100*alloc){ + buf=realloc(buf,((unsigned int)((length+totallength)/100)+1)*100); + bufptr=buf+totallength; + } + STRNCAT(bufptr,arg,length); + totallength+=length; + } + va_end (ap); + do_log_call(src, buf, totallength, type, level, destmask); +} +void do_log_call(const struct log_source src, const char *msg, unsigned int msglength, unsigned int type, unsigned int level, unsigned int destmask){ + if(EGong_global_configuration.log.level>level){ + return; + } + int error=errno; + char msgdest[msglength+src.file.l+src.line.l+src.func.l+50]; + const char *msgptr=msgdest; + char *msgbuf=msgdest; + unsigned int length=0; + if(type!=LOG_TYPE_RAW){ + STRCAT(msgbuf,"[") + STRNCAT(msgbuf, log_levels[level].name, strlen(log_levels[level].name)); + STRCAT(msgbuf,"] "); + + STRNCAT(msgbuf,src.file.v, src.file.l-1); + STRCAT(msgbuf,":"); + STRNCAT(msgbuf, src.line.v, src.line.l-1); + STRCAT(msgbuf,", "); + STRNCAT(msgbuf, src.func.v, src.func.l-1); + STRCAT(msgbuf,": "); + + STRNCAT(msgbuf, msg, msglength); + if(type==LOG_TYPE_SIGNAL){ + char *err=strerror(error); + STRCAT(msgbuf,"("); + STRNCAT(msgbuf, err,strlen(err)); + STRCAT(msgbuf,")"); + } + #ifdef _WIN32 + else if(type==LOG_TYPE_SOCKET){ + STRCAT(msgbuf,"("); + LPVOID lpMsgBuf; + int e; + + lpMsgBuf = (LPVOID)"Unknown error"; + e = WSAGetLastError(); + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, e, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, 0, NULL)) { + STRNCAT(msgbuf, lpMsgBuf,strlen(lpMsgBuf)); + LocalFree(lpMsgBuf); + } + else{ + STRCAT(msgbuf,"Unknown"); + } + STRCAT(msgbuf,")"); + } + #endif + STRCAT(msgbuf,"\n\0"); + length=(unsigned int)(msgbuf-msgptr); + } + else{ + msgptr=msg; + length=msglength; + } + if((destmask&LOG_DEST_STDIO)>0){ + log_write_stdio(msgptr,length, type, level); + } +} diff --git a/src/Util/Misc.c b/src/Util/Misc.c @@ -0,0 +1,12 @@ +#include <EGong/Util/Misc.h> +#include <EGong/Util/Log.h> +#include <openssl/rand.h> + +int EGong_misc_get_rand(char *dest, size_t length){ + RAND_pseudo_bytes((unsigned char *)dest, length); + return 0; +} + +int EGong_array_init(){ + return 0; +} diff --git a/src/Util/Socket.c b/src/Util/Socket.c @@ -0,0 +1,156 @@ +#include <EGong/Util/Socket.h> +#include <EGong/Util/Config.h> +#include <EGong/Util/Log.h> +#include <EGong/Packet.h> + +#ifdef _WIN32 + #include <windows.h> + #include <winsock2.h> + #include <ws2tcpip.h> + #include <iphlpapi.h> +#else + #include <sys/socket.h> + #include <sys/types.h> + #include <arpa/inet.h> + #include <stdlib.h> + #include <string.h> + #include <unistd.h> + #include <netinet/in.h> +#endif +#include <fcntl.h> +#include <errno.h> + +SOCKET EGong_listen_sock; + +#ifdef _WIN32 +WSADATA wsaData; +int inet_aton(const char *cp, struct in_addr *inp){ + inp->s_addr=inet_addr(cp); + if(inp->s_addr==-1){ + return 0; + } + else{ + return 1; + } +} +#endif + +int EGong_sockets_setup(void){ + #ifdef _WIN32 + int res=WSAStartup(MAKEWORD(2,2), &wsaData); + if(res!=0) { + do_log("WSAStartup failed", LOG_TYPE_NORMAL, LOG_LEVEL_FATAL); + return -1; + } + #endif + return 0; +} +int EGong_sockets_shutdown(void){ + #ifdef _WIN32 + WSACleanup(); + #endif + return 0; +} + +void EGong_socket_close(SOCKET *sock){ + #ifdef _WIN32 + closesocket(*sock); + #else + close(*sock); + #endif +} +int EGong_socket_open(SOCKET *sock){ + *sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(*sock<0){ + do_log("Couldn't initialize socket",LOG_TYPE_SIGNAL, LOG_LEVEL_ERROR); + EGong_socket_close(sock); + return -1; + } + return 0; +} +int EGong_sockaddr_init(struct sockaddr_in *addr, const char *ip, unsigned int port, sa_family_t family){ + memset(addr, 0, sizeof(*addr)); + if(inet_aton((char *)ip,&addr->sin_addr)<0){ + do_log("Couldn't convert bind address", LOG_TYPE_SIGNAL, LOG_LEVEL_ERROR); + return -1; + } + addr->sin_family = family; + addr->sin_port = htons(port); + return 0; +} +int EGong_listener_init(SOCKET *sock, struct EGong_config_server *config){ + struct sockaddr_in listen_server; + + if(config==NULL) + config=&EGong_global_configuration.server; + if(sock==NULL) + sock=&EGong_listen_sock; + + if(EGong_socket_open(sock)<0){ + do_log("Couldn't open socket",LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + return -1; + } + #ifdef _WIN32 + unsigned long nonblocking_long=1; + if (ioctlsocket(*sock, FIONBIO, &nonblocking_long)==SOCKET_ERROR){ + do_log("Couldn't set listensocket nonblocking",LOG_TYPE_SIGNAL, LOG_LEVEL_ERROR); + } + #endif + if(EGong_sockaddr_init(&listen_server, config->bind_ip, config->port, AF_INET)<0){ + do_log("Couldn't initialize address",LOG_TYPE_NORMAL, LOG_LEVEL_ERROR); + EGong_socket_close(sock); + return -2; + } + + if(bind(*sock, (struct sockaddr *) &listen_server, sizeof(listen_server))<0){ + do_log("Couldn't bind to sock", LOG_TYPE_SOCKET, LOG_LEVEL_ERROR); + EGong_socket_close(sock); + return -3; + } + do_log("Listening on socket...",LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + return 0; +} +int EGong_listener_get(SOCKET *sock, char *dest, int length, struct sockaddr *source, int flags){ + if(sock==NULL) + sock=&EGong_listen_sock; + int ret; + socklen_t size=sizeof(*source); + if(source==NULL){ + struct sockaddr test; + source=&test; + } + do_log("Receiving on socket...",LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + ret=recvfrom(*sock,dest,length, flags, source, &size); + #ifdef _WIN32 + if((flags&MSG_PEEK)>0&&ret==-1&&WSAGetLastError()==WSAEMSGSIZE){ + return length; + } + else if((flags&MSG_DONTWAIT)>0&&ret==-1&&(WSAGetLastError()==WSAEWOULDBLOCK)) { + #else + if((flags&MSG_DONTWAIT)>0&&ret==-1&&(errno==EAGAIN||errno==EWOULDBLOCK)) { + #endif + return 0; + } + else if(ret<0){ + do_log("Couldn't receive from socket", LOG_TYPE_SOCKET, LOG_LEVEL_ERROR); + return -1; + } + return ret; +} +void EGong_listener_close(SOCKET *sock){ + if(sock==NULL){ + sock=&EGong_listen_sock; + } + EGong_socket_close(sock); +} +int EGong_sendto(SOCKET *sock, const char *dest, const char *msg, size_t msg_len, struct EGong_config_server *config){ + struct sockaddr_in server; + if(config==NULL) + config=&EGong_global_configuration.server; + EGong_sockaddr_init(&server, dest, config->port, AF_INET); + int ret=sendto(*sock, msg, msg_len, 0, (struct sockaddr *)&server, sizeof(server)); + if(ret!=msg_len){ + do_log("Error while sending message", LOG_TYPE_SIGNAL, LOG_LEVEL_ERROR); + } + return ret; +} diff --git a/src/Util/Waiter.c b/src/Util/Waiter.c @@ -0,0 +1,70 @@ +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <EGong/Util/Waiter.h> +#include <EGong/Interfaces.h> +#include <EGong/Util/Log.h> +#include <EGong/Util/Config.h> +#ifdef _WIN32 + #include <winsock2.h> +#endif +#ifdef USE_GTK + #include <gtk/gtk.h> + + gboolean Egong_waiter_gtk_callback(GIOChannel *source, GIOCondition condition, gpointer data){ + EGong_interface_cycle(); + return G_SOURCE_CONTINUE; + } +#endif + + +fd_set EGong_waiter_fds; +unsigned int EGong_waiter_highest_fd; +unsigned int EGong_waiter_cnt=0; +int EGong_waiter_init(void){ + FD_ZERO(&EGong_waiter_fds); + return 0; +} +int EGong_waiter_add(int sock, unsigned short int type){ + EGong_waiter_cnt++; + #ifdef _WIN32 + if(type==EGONG_WAITER_FD){ + do_log("Adding filedescriptors not supported, sorry", LOG_TYPE_NORMAL, LOG_LEVEL_WARNING); + return 1; + } + #endif + do_log("Adding to waiter...", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + FD_SET(sock, &EGong_waiter_fds); + if(EGong_waiter_highest_fd<sock){ + EGong_waiter_highest_fd=sock; + } + #ifdef USE_GTK + GIOChannel *new=g_io_channel_unix_new(sock); + g_io_add_watch(new,G_IO_IN|G_IO_ERR|G_IO_HUP, Egong_waiter_gtk_callback, NULL); + #endif + return 0; +} +int EGong_waiter_del(int sock){ + FD_SET(sock, &EGong_waiter_fds); + EGong_waiter_cnt--; + return 0; +} +int EGong_waiter_wait(void){ + if(EGong_waiter_cnt==0){ + do_log("Nothing to wait for...", LOG_TYPE_NORMAL, LOG_LEVEL_INFO); + return 1; + } + do_log("Waiting...", LOG_TYPE_NORMAL, LOG_LEVEL_DEBUG); + struct timeval *tv=NULL; + #ifdef _WIN32 + struct timeval tv2; + tv2.tv_sec=2; + tv2.tv_usec=0; + tv=&tv2; + #endif + if(select(EGong_waiter_highest_fd+1, &EGong_waiter_fds, NULL, NULL, tv)<0){ + do_log("Couldnt select", LOG_TYPE_SIGNAL, LOG_LEVEL_ERROR); + return -1; + } + return 0; +}