mirror of
https://github.com/eddyem/eddys_snippets.git
synced 2025-12-06 02:35:12 +03:00
add serialsock
This commit is contained in:
parent
786ed54d03
commit
9192ee09a3
23
NES_webiface/.gitignore
vendored
Normal file
23
NES_webiface/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
*.o
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
|
||||||
|
# qt-creator
|
||||||
|
*.config
|
||||||
|
*.cflags
|
||||||
|
*.cxxflags
|
||||||
|
*.creator*
|
||||||
|
*.files
|
||||||
|
*.includes
|
||||||
71
NES_webiface/CMakeLists.txt
Normal file
71
NES_webiface/CMakeLists.txt
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
set(PROJ NES_web)
|
||||||
|
set(MINOR_VERSION "1")
|
||||||
|
set(MID_VERSION "0")
|
||||||
|
set(MAJOR_VERSION "0")
|
||||||
|
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
||||||
|
|
||||||
|
project(${PROJ} VERSION ${PROJ_VERSION} LANGUAGES C)
|
||||||
|
|
||||||
|
message("VER: ${VERSION}")
|
||||||
|
|
||||||
|
# default flags
|
||||||
|
set(CMAKE_C_FLAGS_RELEASE "")
|
||||||
|
set(CMAKE_C_FLAGS_DEBUG "")
|
||||||
|
set(CMAKE_C_FLAGS "-O2 -std=gnu99")
|
||||||
|
|
||||||
|
set(CMAKE_COLOR_MAKEFILE ON)
|
||||||
|
|
||||||
|
# here is one of two variants: all .c in directory or .c files in list
|
||||||
|
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SOURCES)
|
||||||
|
|
||||||
|
# cmake -DDEBUG=1 -> debugging
|
||||||
|
if(DEFINED EBUG)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wall -Werror -W")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wall -Werror -W")
|
||||||
|
set(CMAKE_BUILD_TYPE DEBUG)
|
||||||
|
set(CMAKE_VERBOSE_MAKEFILE "ON")
|
||||||
|
add_definitions(-DEBUG)
|
||||||
|
else()
|
||||||
|
set(CMAKE_BUILD_TYPE RELEASE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#pthreads
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
###### pkgconfig ######
|
||||||
|
# pkg-config modules (for pkg-check-modules)
|
||||||
|
set(MODULES usefull_macros sqlite3)
|
||||||
|
|
||||||
|
# find packages:
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(${PROJ} REQUIRED ${MODULES})
|
||||||
|
|
||||||
|
###### additional flags ######
|
||||||
|
list(APPEND ${PROJ}_LIBRARIES "-lonion -lcrypt")
|
||||||
|
|
||||||
|
# change wrong behaviour with install prefix
|
||||||
|
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND CMAKE_INSTALL_PREFIX MATCHES "/usr/local")
|
||||||
|
else()
|
||||||
|
message("Change default install path to /usr/local")
|
||||||
|
set(CMAKE_INSTALL_PREFIX "/usr/local")
|
||||||
|
endif()
|
||||||
|
message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}")
|
||||||
|
|
||||||
|
# exe file
|
||||||
|
add_executable(${PROJ} ${SOURCES})
|
||||||
|
# -I
|
||||||
|
include_directories(${${PROJ}_INCLUDE_DIRS})
|
||||||
|
# -L
|
||||||
|
link_directories(${${PROJ}_LIBRARY_DIRS})
|
||||||
|
# -D
|
||||||
|
add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||||
|
-DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\"
|
||||||
|
-DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\"
|
||||||
|
-DMAJOR_VERSION=\"${MAJOR_VESION}\")
|
||||||
|
|
||||||
|
# -l
|
||||||
|
target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} -lm)
|
||||||
|
|
||||||
|
# Installation of the program
|
||||||
|
INSTALL(TARGETS ${PROJ} DESTINATION "bin")
|
||||||
5
NES_webiface/HOWTO.cert
Normal file
5
NES_webiface/HOWTO.cert
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
create:
|
||||||
|
openssl req -newkey rsa:2048 -nodes -keyout cert.key -x509 -days 365 -out cert.pem
|
||||||
|
|
||||||
|
review:
|
||||||
|
openssl x509 -text -noout -in cert.pem
|
||||||
3
NES_webiface/README.md
Normal file
3
NES_webiface/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# NES_web
|
||||||
|
|
||||||
|
Web-interface for NES (Nesmith Echelle Spectrograph) management. Based on pusirobot and liboninon.
|
||||||
682
NES_webiface/auth.c
Normal file
682
NES_webiface/auth.c
Normal file
@ -0,0 +1,682 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the NES_web project.
|
||||||
|
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <crypt.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <onion/dict.h>
|
||||||
|
#include <onion/log.h>
|
||||||
|
#include <onion/types_internal.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "auth.h"
|
||||||
|
|
||||||
|
extern char *onion_sessions_generate_id();
|
||||||
|
extern void onion_random_init();
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
sqlite3 *db; // session database
|
||||||
|
char *name; // database filename
|
||||||
|
sqlite3_stmt *add; // template to add/modify session
|
||||||
|
sqlite3_stmt *getsid; // get data by session ID
|
||||||
|
sqlite3_stmt *getsockid;// get data by socked ID
|
||||||
|
sqlite3_stmt *delold; // delete all old sessions (with atime < XX)
|
||||||
|
sqlite3_stmt *del; // delete session
|
||||||
|
pthread_mutex_t mutex; // locking mutex
|
||||||
|
} _sessionDB;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
sqlite3 *db; // auth database
|
||||||
|
char *name; // database filename
|
||||||
|
sqlite3_stmt *add; // add user data
|
||||||
|
sqlite3_stmt *get; // get user data by username
|
||||||
|
sqlite3_stmt *del; // delete user data
|
||||||
|
pthread_mutex_t mutex; // locking mutex
|
||||||
|
} _authDB;
|
||||||
|
|
||||||
|
static _sessionDB *sessionDB = NULL;
|
||||||
|
static _authDB *authDB = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getQdata - find data in POST or GET parts
|
||||||
|
* @param req - request
|
||||||
|
* @param key - searching key
|
||||||
|
* @return value or NULL
|
||||||
|
*/
|
||||||
|
const char *getQdata(onion_request *req, const char *key){
|
||||||
|
if(!req || !key) return NULL;
|
||||||
|
printf("key %s, ", key);
|
||||||
|
const char *data = onion_request_get_query(req, key);
|
||||||
|
printf("GET: '%s' ", data);
|
||||||
|
if(!data){
|
||||||
|
data = onion_request_get_post(req, key);
|
||||||
|
if(data && *data == 0) data = NULL;
|
||||||
|
printf("POST: '%s'", data);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
fflush(stdout);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sqprep - prepare SQLite statement
|
||||||
|
* @param db - database
|
||||||
|
* @param str - text string for statement
|
||||||
|
* @param stmt - the statement
|
||||||
|
* @return 0 if all OK
|
||||||
|
*/
|
||||||
|
static int sqprep(sqlite3 *db, const char *str, sqlite3_stmt **stmt){
|
||||||
|
int rc = sqlite3_prepare_v2(db, str, (int)strlen(str), stmt, NULL);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
WARNX("Can't prepare statement to save (%d)", rc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief addtext - bind text phrase to statement
|
||||||
|
* @param stmt - the statement
|
||||||
|
* @param narg - argument number for binding
|
||||||
|
* @param str - the text itself
|
||||||
|
* @return 0 if all OK
|
||||||
|
*/
|
||||||
|
static int addtext(sqlite3_stmt *stmt, int narg, const char *str){
|
||||||
|
if(str == NULL) str = "";
|
||||||
|
int rc = sqlite3_bind_text(stmt, narg, str, -1, SQLITE_TRANSIENT);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
WARNX("Can't bind %s: %d", str, rc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief addWSkey - add new websocket ID to session & send this ID to user
|
||||||
|
* @param res - web response
|
||||||
|
* @param session - session information to modify
|
||||||
|
*/
|
||||||
|
void addWSkey(onion_response *res, sessinfo *session){
|
||||||
|
if(!res || !session) return;
|
||||||
|
do{
|
||||||
|
FREE(session->sockID);
|
||||||
|
session->sockID = onion_sessions_generate_id();
|
||||||
|
DBG("Try to modify session %s", session->sessID);
|
||||||
|
if(!addSession(session, 1)){
|
||||||
|
DBG("Modify session: ID=%s, sockid=%s, atime=%" PRId64 ", user=%s, data=%s\n",
|
||||||
|
session->sessID, session->sockID, session->atime, session->username, session->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}while(1);
|
||||||
|
onion_response_write0(res, session->sockID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief qookieSession - find session ID from SESSION_COOKIE_NAME and search session in DB
|
||||||
|
* @param req - web request
|
||||||
|
* @return session data (allocated here) or NULL if session not found
|
||||||
|
*/
|
||||||
|
sessinfo *qookieSession(onion_request *req){
|
||||||
|
if(!req) return NULL;
|
||||||
|
/*const char *path = onion_request_get_path(req);
|
||||||
|
printf("Ask path %s\n", path);*/
|
||||||
|
onion_dict *cookies = onion_request_get_cookies_dict(req);
|
||||||
|
const char *skey = onion_dict_get(cookies, SESSION_COOKIE_NAME);
|
||||||
|
if(!skey){
|
||||||
|
WARNX("No session cookie found\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return getSession(skey);
|
||||||
|
}
|
||||||
|
|
||||||
|
onion_connection_status auth(_U_ onion_handler *h, onion_request *req, onion_response *res){
|
||||||
|
if(!req || !res) return OCS_CLOSE_CONNECTION;
|
||||||
|
if(onion_request_get_flags(req) & OR_HEAD) {
|
||||||
|
onion_response_write_headers(res);
|
||||||
|
return OCS_PROCESSED;
|
||||||
|
}
|
||||||
|
const char *host = onion_request_get_client_description(req);
|
||||||
|
char json[2048]; // json buffer for UA & IP
|
||||||
|
const char *UA = onion_request_get_header(req, "User-Agent");
|
||||||
|
snprintf(json, 2048, "{\"User-Agent\": \"%s\", \"User-IP\": \"%s\"}", UA, host);
|
||||||
|
DBG("Client: %s, UA: %s\n", host, UA);
|
||||||
|
const char *logout = getQdata(req, "LogOut");
|
||||||
|
DBG("logout=%s\n", logout);
|
||||||
|
sessinfo *session = qookieSession(req);
|
||||||
|
if(!session) DBG("No cookie, need to create\n");
|
||||||
|
else if(!logout){
|
||||||
|
onion_response_write0(res, AUTH_ANS_AUTHOK);
|
||||||
|
goto closeconn;
|
||||||
|
}
|
||||||
|
const char *username = NULL, *passwd = NULL;
|
||||||
|
if(logout){
|
||||||
|
DBG("User logged out\n");
|
||||||
|
if(session){
|
||||||
|
if(deleteSession(session->sessID))
|
||||||
|
WARNX("Can't delete session with ID=%s from database", session->sessID);
|
||||||
|
}
|
||||||
|
onion_response_write0(res, AUTH_ANS_LOGOUT);
|
||||||
|
onion_response_add_cookie(res, SESSION_COOKIE_NAME, "clear", 0, "/", NULL, OC_HTTP_ONLY|OC_SECURE);
|
||||||
|
goto closeconn;
|
||||||
|
}else{ // log in
|
||||||
|
freeSessInfo(&session);
|
||||||
|
username = getQdata(req, "login");
|
||||||
|
if(!username){
|
||||||
|
ONION_WARNING("no login field -> need auth");
|
||||||
|
onion_response_write0(res, AUTH_ANS_NEEDAUTH);
|
||||||
|
return OCS_CLOSE_CONNECTION;
|
||||||
|
}
|
||||||
|
passwd = getQdata(req, "passwd");
|
||||||
|
if(!passwd){
|
||||||
|
ONION_WARNING("Trying to enter authenticated area without password");
|
||||||
|
onion_response_write0(res, AUTH_ANS_NOPASSWD);
|
||||||
|
return OCS_FORBIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userinfo *U = getUserData(username);
|
||||||
|
if(!U){
|
||||||
|
WARNX("User %s not found", username);
|
||||||
|
return OCS_FORBIDDEN;
|
||||||
|
}
|
||||||
|
char *pass = strdup(crypt(passwd, "$6$"));
|
||||||
|
if(!pass){
|
||||||
|
WARN("Error in ctypt or strdup");
|
||||||
|
freeUserInfo(&U);
|
||||||
|
return OCS_FORBIDDEN;
|
||||||
|
}
|
||||||
|
int comp = strcmp(pass, U->password);
|
||||||
|
freeUserInfo(&U);
|
||||||
|
FREE(pass);
|
||||||
|
if(comp){
|
||||||
|
WARNX("User %s give wrong password", username);
|
||||||
|
return OCS_FORBIDDEN;
|
||||||
|
}
|
||||||
|
session = MALLOC(sessinfo, 1);
|
||||||
|
session->atime = time(NULL);
|
||||||
|
session->username = strdup(username);
|
||||||
|
/*
|
||||||
|
onion_dict *data = onion_dict_new();
|
||||||
|
onion_dict_add(data, "UA", UA, 0);
|
||||||
|
onion_dict_add(data, "IP", host, 0);
|
||||||
|
onion_block *bl = onion_dict_to_json(data);
|
||||||
|
if(bl){
|
||||||
|
const char *json = onion_block_data(bl);
|
||||||
|
if(json) session->data = strdup(json);
|
||||||
|
}*/
|
||||||
|
session->data = strdup(json);
|
||||||
|
do{
|
||||||
|
FREE(session->sessID);
|
||||||
|
session->sessID = onion_sessions_generate_id();
|
||||||
|
DBG("Try to add session %s", session->sessID);
|
||||||
|
if(!addSession(session, 0)){
|
||||||
|
DBG("New session: ID=%s, atime=%" PRId64 ", user=%s, data=%s\n",
|
||||||
|
session->sessID, session->atime, session->username, session->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep(2);
|
||||||
|
}while(1);
|
||||||
|
onion_response_add_cookie(res, SESSION_COOKIE_NAME, session->sessID, 366*86400, "/", NULL, OC_HTTP_ONLY|OC_SECURE);
|
||||||
|
onion_response_write0(res, AUTH_ANS_AUTHOK);
|
||||||
|
closeconn:
|
||||||
|
freeSessInfo(&session);
|
||||||
|
return OCS_CLOSE_CONNECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief opendb - open SQLite database
|
||||||
|
* @param name - database filename
|
||||||
|
* @param db - database itself
|
||||||
|
* @return 0 if all OK
|
||||||
|
*/
|
||||||
|
static int opendb(const char *name, sqlite3 **db){
|
||||||
|
if(!name || !db) return 2;
|
||||||
|
if(SQLITE_OK != sqlite3_open(name, db)){
|
||||||
|
ONION_ERROR("Can't open database: %s", sqlite3_errmsg(*db));
|
||||||
|
sqlite3_close(*db);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief close_sessDB - close session database & free memory
|
||||||
|
*/
|
||||||
|
static void close_sessDB(){
|
||||||
|
if(!sessionDB) return;
|
||||||
|
pthread_mutex_lock(&sessionDB->mutex);
|
||||||
|
sqlite3_finalize(sessionDB->add);
|
||||||
|
sqlite3_finalize(sessionDB->del);
|
||||||
|
sqlite3_finalize(sessionDB->getsid);
|
||||||
|
sqlite3_finalize(sessionDB->getsockid);
|
||||||
|
sqlite3_close(sessionDB->db);
|
||||||
|
pthread_mutex_unlock(&sessionDB->mutex);
|
||||||
|
pthread_mutex_destroy(&sessionDB->mutex);
|
||||||
|
FREE(sessionDB->name);
|
||||||
|
FREE(sessionDB);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief close_authDB - close user database & free memory
|
||||||
|
*/
|
||||||
|
static void close_authDB(){
|
||||||
|
if(!authDB) return;
|
||||||
|
pthread_mutex_lock(&authDB->mutex);
|
||||||
|
sqlite3_finalize(authDB->add);
|
||||||
|
sqlite3_finalize(authDB->del);
|
||||||
|
sqlite3_finalize(authDB->get);
|
||||||
|
sqlite3_close(authDB->db);
|
||||||
|
pthread_mutex_unlock(&authDB->mutex);
|
||||||
|
pthread_mutex_destroy(&authDB->mutex);
|
||||||
|
FREE(authDB->name);
|
||||||
|
FREE(authDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief closeSQLite - close all databases
|
||||||
|
*/
|
||||||
|
void closeSQLite(){
|
||||||
|
close_authDB();
|
||||||
|
close_sessDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief initSQLite - init SQL databases
|
||||||
|
* @param auth_filename - database with auth data (username, password hash, access level)
|
||||||
|
* @param sess_filename - session database (session ID, websosket ID, access time, data {UA, IP, username, access level - JSON})
|
||||||
|
* @return error code or 0 if OK
|
||||||
|
*/
|
||||||
|
int initSQLite(const char *auth_filename, const char *sess_filename){
|
||||||
|
if(!auth_filename || !sess_filename) return 5;
|
||||||
|
int rc;
|
||||||
|
char *zErrMsg = NULL;
|
||||||
|
onion_random_init();
|
||||||
|
closeSQLite();
|
||||||
|
/******************************* users database *******************************/
|
||||||
|
authDB = MALLOC(_authDB, 1);
|
||||||
|
if(opendb(auth_filename, &authDB->db)) return 2;
|
||||||
|
authDB->name = strdup(auth_filename);
|
||||||
|
rc = sqlite3_exec(authDB->db, "CREATE TABLE passwd (user TEXT PRIMARY KEY NOT NULL, passhash TEXT, level INT, comment TEXT)", NULL, NULL, &zErrMsg);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
if(strcmp(zErrMsg, "table passwd already exists")){
|
||||||
|
WARNX("SQL CREATE error %d: %s", rc, zErrMsg);
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
fprintf(stderr, "Add default user\n");
|
||||||
|
// default admin: toor, password: p@ssw0rd
|
||||||
|
rc = sqlite3_exec(authDB->db, "INSERT INTO passwd VALUES (\"toor\", \"$6$$F55h0JlnNG19zS6YHUDX6h4zksblEBCFRqzCoCt6Y3VqE7zBeM/ifdGbUNMK.dLIwu9jq3fCmLBYEpzEpNCej0\", 0, \"\")", NULL, NULL, &zErrMsg);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
fprintf(stderr, "SQL INSERT error %d: %s\n", rc, zErrMsg);
|
||||||
|
sqlite3_free(zErrMsg);
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// get user information
|
||||||
|
if(sqprep(authDB->db, "SELECT passhash, level, comment FROM passwd WHERE user=?",
|
||||||
|
&authDB->get)) goto ret;
|
||||||
|
// add or modify user
|
||||||
|
if(sqprep(authDB->db, "INSERT OR REPLACE INTO passwd (user, passhash, level, comment) VALUES (?, ?, ?, ?)",
|
||||||
|
&authDB->add)) goto ret;
|
||||||
|
// delete user
|
||||||
|
if(sqprep(authDB->db, "DELETE FROM passwd WHERE user=?", &authDB->del)) goto ret;
|
||||||
|
if(pthread_mutex_init(&authDB->mutex, NULL)){
|
||||||
|
WARN("Can't init authDB mutex");
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
/****************************** session database ******************************/
|
||||||
|
sessionDB = MALLOC(_sessionDB, 1);
|
||||||
|
if(opendb(sess_filename, &sessionDB->db)) goto ret;
|
||||||
|
sessionDB->name = strdup(sess_filename);
|
||||||
|
rc = sqlite3_exec(sessionDB->db, "CREATE TABLE sessions (sessID TEXT PRIMARY KEY NOT NULL, sockID TEXT, atime INT, username TEXT, data TEXT)", NULL, NULL, &zErrMsg);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
if(strcmp(zErrMsg, "table sessions already exists")){
|
||||||
|
WARNX("SQL CREATE error %d: %s", rc, zErrMsg);
|
||||||
|
sqlite3_free(zErrMsg);
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// get session information
|
||||||
|
if(sqprep(sessionDB->db, "SELECT sockID, atime, username, data FROM sessions WHERE sessID=?",
|
||||||
|
&sessionDB->getsid)) goto ret;
|
||||||
|
if(sqprep(sessionDB->db, "SELECT sessID, atime, username, data FROM sessions WHERE sockID=?",
|
||||||
|
&sessionDB->getsockid)) goto ret;
|
||||||
|
// add or modify session
|
||||||
|
if(sqprep(sessionDB->db, "INSERT OR REPLACE INTO sessions (sessID, sockID, atime, username, data) VALUES (?, ?, ?, ?, ?)",
|
||||||
|
&sessionDB->add)) goto ret;
|
||||||
|
// delete session
|
||||||
|
if(sqprep(sessionDB->db, "DELETE FROM sessions WHERE sessID=?",
|
||||||
|
&sessionDB->del)) goto ret;
|
||||||
|
if(sqprep(sessionDB->db, "DELETE FROM sessions WHERE atime<?",
|
||||||
|
&sessionDB->delold)) goto ret;
|
||||||
|
return 0;
|
||||||
|
ret:
|
||||||
|
closeSQLite();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getUserData - find all records in authDB for given username
|
||||||
|
* @param username - user name
|
||||||
|
* @return userinfo structure allocated here or NULL if user not found
|
||||||
|
*/
|
||||||
|
userinfo *getUserData(const char *username){
|
||||||
|
if(!username) return NULL;
|
||||||
|
userinfo *U = NULL;
|
||||||
|
if(!authDB){
|
||||||
|
WARNX("User database not initialized");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&authDB->mutex);
|
||||||
|
sqlite3_reset(authDB->get);
|
||||||
|
if(addtext(authDB->get, 1, username)) return NULL;
|
||||||
|
if(SQLITE_ROW != sqlite3_step(authDB->get)){
|
||||||
|
WARNX("User %s not found", username);
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
const char *pass = (const char *) sqlite3_column_text(authDB->get, 0);
|
||||||
|
int levl = sqlite3_column_int(authDB->get, 1);
|
||||||
|
const char *comment = (const char *) sqlite3_column_text(authDB->get, 2);
|
||||||
|
U = (userinfo *) malloc(sizeof(userinfo));
|
||||||
|
if(!U) goto ret;
|
||||||
|
U->username = strdup(username);
|
||||||
|
U->password = strdup(pass);
|
||||||
|
U->level = levl;
|
||||||
|
U->comment = strdup(comment);
|
||||||
|
ret:
|
||||||
|
pthread_mutex_unlock(&authDB->mutex);
|
||||||
|
return U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief freeUserInfo - free memory for struct userinfo
|
||||||
|
* @param x - pointer to userinfo pointer
|
||||||
|
*/
|
||||||
|
void freeUserInfo(userinfo **x){
|
||||||
|
if(!x || !*x) return;
|
||||||
|
userinfo *U = *x;
|
||||||
|
free(U->username);
|
||||||
|
free(U->password);
|
||||||
|
free(U->comment);
|
||||||
|
free(U);
|
||||||
|
*x = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback for showAllUsers()
|
||||||
|
static int selallcb(_U_ void *notused, int argc, char **argv, _U_ char **no){
|
||||||
|
if(argc != 4){
|
||||||
|
fprintf(stderr, "Wrong argc: %d\n", argc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("%s\t%s\t%s\t%s\n", argv[0], argv[2], argv[1], argv[3]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief showAllUsers - printout user database
|
||||||
|
*/
|
||||||
|
void showAllUsers(){
|
||||||
|
char *zErrMsg = NULL;
|
||||||
|
green("\nUSER\tLevel\tPassHash\t\t\tComment\n");
|
||||||
|
pthread_mutex_lock(&authDB->mutex);
|
||||||
|
int rc = sqlite3_exec(authDB->db, "SELECT * FROM passwd GROUP BY user", selallcb, NULL, &zErrMsg);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
WARNX("SQL CREATE error %d: %s", rc, zErrMsg);
|
||||||
|
sqlite3_free(zErrMsg);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&authDB->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deleteUser - delete user record from database
|
||||||
|
* @param username - user name
|
||||||
|
* @return 0 if all OK
|
||||||
|
*/
|
||||||
|
int deleteUser(const char *username){
|
||||||
|
if(!username) return 1;
|
||||||
|
userinfo *u = getUserData(username);
|
||||||
|
if(!u) return 1;
|
||||||
|
FREE(u);
|
||||||
|
pthread_mutex_lock(&authDB->mutex);
|
||||||
|
sqlite3_reset(authDB->del);
|
||||||
|
if(addtext(authDB->del, 1, username)) goto reterr;
|
||||||
|
if(SQLITE_DONE != sqlite3_step(authDB->del)) goto reterr;
|
||||||
|
else{
|
||||||
|
printf("User %s deleted\n", username);
|
||||||
|
pthread_mutex_unlock(&authDB->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
reterr:
|
||||||
|
pthread_mutex_unlock(&authDB->mutex);
|
||||||
|
WARNX("Can't delete user %s", username);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief addUser - add user to database
|
||||||
|
* @param User - struct with user data
|
||||||
|
* @return 0 if OK
|
||||||
|
*/
|
||||||
|
int addUser(userinfo *User){
|
||||||
|
if(!User) return 1;
|
||||||
|
if(strlen(User->username) < 1){
|
||||||
|
WARNX("No username");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&authDB->mutex);
|
||||||
|
sqlite3_reset(authDB->add);
|
||||||
|
if(addtext(authDB->add, 1, User->username)) goto reterr;
|
||||||
|
if(addtext(authDB->add, 2, User->password)) goto reterr;
|
||||||
|
if(SQLITE_OK != sqlite3_bind_int(authDB->add, 3, User->level)) goto reterr;
|
||||||
|
addtext(authDB->add, 4, User->comment);
|
||||||
|
if(SQLITE_DONE == sqlite3_step(authDB->add)){
|
||||||
|
green("Add to database:\n");
|
||||||
|
printf("\tuser %s, passHash %s, level %d, comment '%s'\n",
|
||||||
|
User->username, User->password, User->level, User->comment);
|
||||||
|
pthread_mutex_unlock(&authDB->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
reterr:
|
||||||
|
pthread_mutex_unlock(&authDB->mutex);
|
||||||
|
WARNX("Can't insert user %s", User->username);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getSession - find session by session ID or socket ID
|
||||||
|
* @param ID - session or socket ID
|
||||||
|
* @return NULL if not found or session structure (allocated here)
|
||||||
|
*/
|
||||||
|
sessinfo *getSession(const char *ID){
|
||||||
|
if(!ID) return NULL;
|
||||||
|
sqlite3_stmt *stmt = sessionDB->getsid;
|
||||||
|
sessinfo *s = NULL;
|
||||||
|
pthread_mutex_lock(&sessionDB->mutex);
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
if(addtext(stmt, 1, ID)) goto ret;
|
||||||
|
const char *sessID = NULL, *sockID = NULL;
|
||||||
|
if(SQLITE_ROW != sqlite3_step(stmt)){
|
||||||
|
stmt = sessionDB->getsockid;
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
if(addtext(stmt, 1, ID)) goto ret;
|
||||||
|
if(SQLITE_ROW != sqlite3_step(stmt)){
|
||||||
|
WARNX("Session %s not found\n", ID);
|
||||||
|
goto ret;
|
||||||
|
}else{
|
||||||
|
sockID = ID;
|
||||||
|
sessID = (const char *) sqlite3_column_text(stmt, 0);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
sessID = ID;
|
||||||
|
sockID = (const char *) sqlite3_column_text(stmt, 0);
|
||||||
|
}
|
||||||
|
// 0-ID, 1-atime, 2-username, 3-data
|
||||||
|
int64_t atime = sqlite3_column_int64(stmt, 1);
|
||||||
|
const char *username = (const char *)sqlite3_column_text(stmt, 2);
|
||||||
|
const char *data = (const char *)sqlite3_column_text(stmt, 3);
|
||||||
|
s = (sessinfo*) malloc(sizeof(sessinfo));
|
||||||
|
if(!s) goto ret;
|
||||||
|
s->sessID = strdup(sessID);
|
||||||
|
s->sockID = strdup(sockID);
|
||||||
|
s->atime = atime;
|
||||||
|
s->username = strdup(username);
|
||||||
|
s->data = strdup(data);
|
||||||
|
ret:
|
||||||
|
pthread_mutex_unlock(&sessionDB->mutex);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief addSession - add new session or modify old
|
||||||
|
* @param s - structure with session information
|
||||||
|
* @param modify != 0 to modify existant session
|
||||||
|
* @return 0 if all OK
|
||||||
|
*/
|
||||||
|
int addSession(sessinfo *s, int modify){
|
||||||
|
if(!s) return 1;
|
||||||
|
sessinfo *byID = getSession(s->sessID);
|
||||||
|
sessinfo *bysID = getSession(s->sockID);
|
||||||
|
if(byID || bysID){ // found session with same IDs
|
||||||
|
if(modify){
|
||||||
|
if(bysID && strcmp(bysID->sessID, s->sessID)){
|
||||||
|
freeSessInfo(&byID);
|
||||||
|
freeSessInfo(&bysID);
|
||||||
|
WARNX("Found another session with the same sockID");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(byID) WARNX("Found another session with the same sessID");
|
||||||
|
if(bysID) WARNX("Found another session with the same sockID");
|
||||||
|
freeSessInfo(&byID);
|
||||||
|
freeSessInfo(&bysID);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&sessionDB->mutex);
|
||||||
|
// 1-sessID, 2-sockID, 3-atime, 4-username, 5-data
|
||||||
|
sqlite3_reset(sessionDB->add);
|
||||||
|
if(addtext(sessionDB->add, 1, s->sessID)) goto reterr;
|
||||||
|
if(addtext(sessionDB->add, 2, s->sockID)) goto reterr;
|
||||||
|
if(SQLITE_OK != sqlite3_bind_int64(sessionDB->add, 3, s->atime)) goto reterr;
|
||||||
|
if(addtext(sessionDB->add, 4, s->username)) goto reterr;
|
||||||
|
if(addtext(sessionDB->add, 5, s->data)) goto reterr;
|
||||||
|
if(SQLITE_DONE == sqlite3_step(sessionDB->add)){
|
||||||
|
pthread_mutex_unlock(&sessionDB->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
reterr:
|
||||||
|
pthread_mutex_unlock(&sessionDB->mutex);
|
||||||
|
WARNX("Can't insert session %s\n", s->sessID);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deleteSession - delete session by SessID
|
||||||
|
* @param sessID - session ID
|
||||||
|
* @return 0 if all OK
|
||||||
|
*/
|
||||||
|
int deleteSession(const char *sessID){
|
||||||
|
if(!sessID) return 1;
|
||||||
|
pthread_mutex_lock(&sessionDB->mutex);
|
||||||
|
sqlite3_reset(sessionDB->del);
|
||||||
|
if(addtext(sessionDB->del, 1, sessID)) goto reterr;
|
||||||
|
if(SQLITE_DONE != sqlite3_step(sessionDB->del)) goto reterr;
|
||||||
|
else{
|
||||||
|
printf("Session with id %s deleted\n", sessID);
|
||||||
|
pthread_mutex_unlock(&sessionDB->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
reterr:
|
||||||
|
pthread_mutex_unlock(&sessionDB->mutex);
|
||||||
|
WARNX("Can't delete session with ID %s\n", sessID);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deleteSession - delete session by SessID
|
||||||
|
* @param minatime - minimal access time (all sessions with atime<minatime will be deleted)
|
||||||
|
* @return 0 if all OK
|
||||||
|
*/
|
||||||
|
int deleteOldSessions(int64_t minatime){
|
||||||
|
pthread_mutex_lock(&sessionDB->mutex);
|
||||||
|
sqlite3_reset(sessionDB->delold);
|
||||||
|
if(SQLITE_OK != sqlite3_bind_int64(sessionDB->delold, 1, minatime)) goto reterr;
|
||||||
|
if(SQLITE_DONE != sqlite3_step(sessionDB->delold)) goto reterr;
|
||||||
|
else{
|
||||||
|
pthread_mutex_unlock(&sessionDB->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
reterr:
|
||||||
|
pthread_mutex_unlock(&sessionDB->mutex);
|
||||||
|
WARNX("Can't delete sessions with atime < %" PRId64 " \n", minatime);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback for showAllSessions
|
||||||
|
static int selallscb(void _U_ *notused, int argc, char **argv, char _U_ **no){
|
||||||
|
if(argc != 5){
|
||||||
|
fprintf(stderr, "Wrong argc: %d\n", argc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("%s\t%s\t%s\t%s\t%s\n", argv[3], argv[2], argv[0], argv[1], argv[4]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void showAllSessions(){
|
||||||
|
char *zErrMsg = NULL;
|
||||||
|
green("Username\tAtime\tSession ID\t\tSocket ID\t\tData\n");
|
||||||
|
int rc = sqlite3_exec(sessionDB->db, "SELECT * FROM sessions ORDER BY username", selallscb, NULL, &zErrMsg);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
WARNX("SQL CREATE error %d: %s\n", rc, zErrMsg);
|
||||||
|
sqlite3_free(zErrMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief freeSessInfo - free session info structure
|
||||||
|
* @param si - address of pointer to SI
|
||||||
|
*/
|
||||||
|
void freeSessInfo(sessinfo **si){
|
||||||
|
if(!si || !*si) return;
|
||||||
|
sessinfo *s = *si;
|
||||||
|
free(s->data);
|
||||||
|
free(s->sessID);
|
||||||
|
free(s->sockID);
|
||||||
|
free(s->username);
|
||||||
|
free(*si);
|
||||||
|
*si = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief vacuum - rebuild databases to free all deleted records
|
||||||
|
*/
|
||||||
|
void vacuumSQLite(){
|
||||||
|
char *zErrMsg = NULL;
|
||||||
|
int rc = sqlite3_exec(authDB->db, "vacuum", NULL, NULL, &zErrMsg);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
WARNX("Error in vacuum %s (%d): %s\n", authDB->name, rc, zErrMsg);
|
||||||
|
sqlite3_free(zErrMsg);
|
||||||
|
}
|
||||||
|
rc = sqlite3_exec(sessionDB->db, "vacuum", NULL, NULL, &zErrMsg);
|
||||||
|
if(rc != SQLITE_OK){
|
||||||
|
WARNX("Error in vacuum %s (%d): %s\n", sessionDB->name, rc, zErrMsg);
|
||||||
|
sqlite3_free(zErrMsg);
|
||||||
|
}
|
||||||
|
green("Both databases are rebuilt\n");
|
||||||
|
}
|
||||||
|
|
||||||
70
NES_webiface/auth.h
Normal file
70
NES_webiface/auth.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the NES_web project.
|
||||||
|
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef AUTH_H__
|
||||||
|
#define AUTH_H__
|
||||||
|
|
||||||
|
#include <onion/onion.h>
|
||||||
|
|
||||||
|
#define SESSION_COOKIE_NAME "Acookie"
|
||||||
|
|
||||||
|
// standard answers to client
|
||||||
|
#define AUTH_ANS_NEEDAUTH "NeedAuth"
|
||||||
|
#define AUTH_ANS_AUTHOK "AuthOK"
|
||||||
|
#define AUTH_ANS_LOGOUT "LogOut"
|
||||||
|
#define AUTH_ANS_NOPASSWD "NoPassword"
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
char *username; // user name
|
||||||
|
char *password; // password hash (SHA512)
|
||||||
|
int level; // user access level
|
||||||
|
char *comment; // optional comment
|
||||||
|
} userinfo;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
char *sessID; // session ID
|
||||||
|
char *sockID; // websoket ID (cleared when disconnected or after 1 minute after `atime`)
|
||||||
|
int64_t atime; // last access time (UNIX time) - all ID data cleared after 1yr of inactivity
|
||||||
|
char *username; // username
|
||||||
|
char *data; // JSON data with UA, IP etc
|
||||||
|
} sessinfo;
|
||||||
|
|
||||||
|
const char *getQdata(onion_request *req, const char *key);
|
||||||
|
onion_connection_status auth(onion_handler *h, onion_request *req, onion_response *res);
|
||||||
|
void addWSkey(onion_response *res, sessinfo *session);
|
||||||
|
|
||||||
|
int initSQLite(const char *auth_filename, const char *sess_filename);
|
||||||
|
void closeSQLite();
|
||||||
|
void vacuumSQLite();
|
||||||
|
|
||||||
|
userinfo *getUserData(const char *username);
|
||||||
|
void freeUserInfo(userinfo **x);
|
||||||
|
void showAllUsers();
|
||||||
|
int deleteUser(const char *username);
|
||||||
|
int addUser(userinfo *User);
|
||||||
|
|
||||||
|
sessinfo *getSession(const char *ID);
|
||||||
|
sessinfo *qookieSession(onion_request *req);
|
||||||
|
int addSession(sessinfo *s, int modify);
|
||||||
|
int deleteSession(const char *sessID);
|
||||||
|
int deleteOldSessions(int64_t minatime);
|
||||||
|
void showAllSessions();
|
||||||
|
void freeSessInfo(sessinfo **si);
|
||||||
|
|
||||||
|
#endif // AUTH_H__
|
||||||
28
NES_webiface/cert.key
Normal file
28
NES_webiface/cert.key
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC68f94gnFpcepC
|
||||||
|
+kpD4bxY7sQAXYbyp5ahAWun4scbLJPjJe56/CE47yvTpdU8KrVfHLYmP8KcF4pM
|
||||||
|
w0ZUNMCEenkQkb+eWjIviw3wzgesqLSssM+GZzlg92V2xkYlS/hEolUh0Z+Gl1Se
|
||||||
|
zl9f1S/EhL6RTfQx5ZuGlppHknqtbP0g4QNkxPXGj/qXqmaWLOxb8fX30eNf/6SF
|
||||||
|
vl1o45xwFE1SSGQnyh8KKZUWAPH2aZWpwwgB8gv4XwaVWo7DirbqOlUhhkylhhl0
|
||||||
|
cA7dHFgODTLluRstYr9M5u3WdoJzTGZTvg2ZV1vmfpQMVbat49TVJYZI3iLKoBHQ
|
||||||
|
IzeSU/lvAgMBAAECggEAUlc40RmTXoBgUHPxtgh9byZrikWnpMWQIQaBJodKb3uo
|
||||||
|
/8m7Ssw2zd76jNRkIYYmMOhyilJXI21y6vCvz3MUwMU5AcVQgyzzIeG7mC8HTlNY
|
||||||
|
kR+nqGla6ozNUg1u5AqcJY7itGyiOSP6j6ASfiFmUsatMU8GmduqLxOyjIfGJRA1
|
||||||
|
hnNAqYsVv2LbhbUQJTBozYMz2XYfiq/GbzL2NC1tv/xWoSL4zELjDuiGyZcT8oyV
|
||||||
|
u+dOf0x/VXOLvHqDrA8HuFbUrBjK5z0QW9iYReti/oxuhGrlp2rJLuzivKr4l+v8
|
||||||
|
qA0momNxhFFgyyx2Mb5zxp9TwA2x7q5Cg3vOCje3MQKBgQDe6MTywxuO4MVpwDSl
|
||||||
|
yot8vzUlI7Bv8BtdW18JUc5y1SIyGHlW1cuaQnZW6hbor6UxAoWi7oIjaFX+JQVD
|
||||||
|
3NLEnjuUF64/Y+k8wtvK0fFeZ2nvx2UNHF50JV0tQZtHo8znwKI/L8ZBSGJcBwh2
|
||||||
|
BGXtJtK9AY6C5xv5U03xRukw/QKBgQDWsn0qd6mV6iGqLth6sjDOJt/RFrvcikXb
|
||||||
|
lMhkCyGPuR2lQsUDbgWMcb/td3CqR5iZAksDbXrPqQBZVm9LO7DfDsL9GxtfgMrt
|
||||||
|
0dWk0Baod/n4NQBn8A6qGpbheFZwOhNGayYI17IqtRJmfLJuR7gRvm/IfGKso24X
|
||||||
|
TTA3kpSl2wKBgEBv52cJ8bB213p/fniiuXnhSDqpO3rQXQi6vhlSlaxqYk069/Cb
|
||||||
|
MxUvu0faua6f/8/QG9OCwQn9QkaKayA3+JGv8CcaRVu7xRO0fJb/45dXq68N4+9L
|
||||||
|
UR6gInRPr9SgzD3+WKiNZfE/PHe/7Lk5AkHw5CCRD6JVrqd/ZlumFQj9AoGBAKae
|
||||||
|
fM7xcRYcTyYRFwYZthC3UKmnOAJO+SoRTHd/v/sXUe+IYvdncjztpmK3eCNeTwoo
|
||||||
|
Imk1lMMGSHQMxXCgkYJ6pU7is5qpjFOGroQqzfrOqZs8HuWLAwZ2fjPbPVH5cC4N
|
||||||
|
R8ZDB01nmzEYgy1c0XhLz9rK1ZVffDfvOoVWZ7BTAoGAdQUkTWTTHU+Xwc9HshJy
|
||||||
|
qDFAFu5SvvO2dn3OvbGVUVc+I3M1P+HMeKS3HnomFLtRRDUGEbqZtPfrxBRnduW9
|
||||||
|
cEtgO+smyq86vs1p/ohmUESB2ablkvOgwXTXus+NsmUt3uVDq+0lFTfog/DX49+O
|
||||||
|
EiTvSXB1U92Opv/kh8ZhQak=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
21
NES_webiface/cert.pem
Normal file
21
NES_webiface/cert.pem
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDazCCAlOgAwIBAgIUU3mUrQDJVG5A00d+WvVFfqScrqIwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||||
|
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA3MTMxNjE0MTlaFw0yMTA3
|
||||||
|
MTMxNjE0MTlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||||
|
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||||
|
AQUAA4IBDwAwggEKAoIBAQC68f94gnFpcepC+kpD4bxY7sQAXYbyp5ahAWun4scb
|
||||||
|
LJPjJe56/CE47yvTpdU8KrVfHLYmP8KcF4pMw0ZUNMCEenkQkb+eWjIviw3wzges
|
||||||
|
qLSssM+GZzlg92V2xkYlS/hEolUh0Z+Gl1Sezl9f1S/EhL6RTfQx5ZuGlppHknqt
|
||||||
|
bP0g4QNkxPXGj/qXqmaWLOxb8fX30eNf/6SFvl1o45xwFE1SSGQnyh8KKZUWAPH2
|
||||||
|
aZWpwwgB8gv4XwaVWo7DirbqOlUhhkylhhl0cA7dHFgODTLluRstYr9M5u3WdoJz
|
||||||
|
TGZTvg2ZV1vmfpQMVbat49TVJYZI3iLKoBHQIzeSU/lvAgMBAAGjUzBRMB0GA1Ud
|
||||||
|
DgQWBBQiHARml0EswF90cHiLYLKxpgj3DjAfBgNVHSMEGDAWgBQiHARml0EswF90
|
||||||
|
cHiLYLKxpgj3DjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB4
|
||||||
|
mMeSGGA4GAfJnxIwRJWGhj2KoweOh9UOVUtvrEJm3LoURbElo1pV3Q3vzt79wLn5
|
||||||
|
JPdXyN/MexYhtq7cwKQps3E4FElmIGUbR4peO/M1z3wJLaXSbaZqeo7ogSW6vzZL
|
||||||
|
xIHuxLtchNOi4rkSmOhzJqJ23cLULIF7Z94nwxXRxqKaIW8hXB7mlV9cDztpn2sz
|
||||||
|
K58M9VYmlfZetoHDzmsymM2DTmmoqR28Ykz+wK+G4U6W1+s7sY3Q+mG91lwvpzTf
|
||||||
|
yvz6dEtqi8ktBdu86E0yHfX04oDyKtl40d0LDzQT5JWhKQFiC25W5tE2p8QLbtHz
|
||||||
|
D5vg23HjTgRHZ80+3e4J
|
||||||
|
-----END CERTIFICATE-----
|
||||||
150
NES_webiface/cmdlnopts.c
Normal file
150
NES_webiface/cmdlnopts.c
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the NES_web project.
|
||||||
|
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* here are global parameters initialisation
|
||||||
|
*/
|
||||||
|
static int help;
|
||||||
|
// global parameters (init with default):
|
||||||
|
glob_pars G = {
|
||||||
|
.port = "8080",
|
||||||
|
.wsport = "8081",
|
||||||
|
.certfile = "cert.pem",
|
||||||
|
.keyfile = "cert.key",
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define command line options by filling structure:
|
||||||
|
* name has_arg flag val type argptr help
|
||||||
|
*/
|
||||||
|
static myoption cmdlnopts[] = {
|
||||||
|
// common options
|
||||||
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")},
|
||||||
|
{"vacuum", NO_ARGS, NULL, 'v', arg_int, APTR(&G.vacuum), _("make \"vacuum\" operation with databases")},
|
||||||
|
{"dumpusers", NO_ARGS, NULL, 'U', arg_int, APTR(&G.dumpUserDB),_("dump users database")},
|
||||||
|
{"dumpsess", NO_ARGS, NULL, 'S', arg_int, APTR(&G.dumpSessDB),_("dump session database")},
|
||||||
|
{"server", NO_ARGS, NULL, 'r', arg_int, APTR(&G.runServer), _("run server process")},
|
||||||
|
{"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), _("server port to listen")},
|
||||||
|
{"wsport", NEED_ARG, NULL, 'P', arg_string, APTR(&G.wsport), _("websocket port to listen (!= server port!)")},
|
||||||
|
{"certfile",NEED_ARG, NULL, 'c', arg_string, APTR(&G.certfile), _("file with SSL certificate")},
|
||||||
|
{"keyfile", NEED_ARG, NULL, 'k', arg_string, APTR(&G.keyfile), _("file with SSL key")},
|
||||||
|
{"usersdb", NEED_ARG, NULL, 'u', arg_string, APTR(&G.usersdb), _("users database filename")},
|
||||||
|
{"sessiondb",NEED_ARG, NULL, 's', arg_string, APTR(&G.sessiondb), _("session database filename")},
|
||||||
|
{"userdel", MULT_PAR, NULL, 'd', arg_string, APTR(&G.userdel), _("user to delete (maybe several)")},
|
||||||
|
{"useradd", NO_ARGS, NULL, 'a', arg_int, APTR(&G.useradd), _("add user[s] interactively")},
|
||||||
|
{"sdatime", NEED_ARG, NULL, 'A', arg_longlong,APTR(&G.delatime), _("minimal atime to delete sessions from DB (-1 for >year)")},
|
||||||
|
{"sessdel", NEED_ARG, NULL, 'l', arg_string, APTR(&G.delsession),_("delete session by sessID or sockID")},
|
||||||
|
{"logfile", NEED_ARG, NULL, 'L', arg_string, APTR(&G.logfilename),_("log file name")},
|
||||||
|
end_option
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse command line options and return dynamically allocated structure
|
||||||
|
* to global parameters
|
||||||
|
* @param argc - copy of argc from main
|
||||||
|
* @param argv - copy of argv from main
|
||||||
|
* @return allocated structure with global parameters
|
||||||
|
*/
|
||||||
|
glob_pars *parse_args(int argc, char **argv){
|
||||||
|
int i;
|
||||||
|
size_t hlen = 1024;
|
||||||
|
char helpstring[1024], *hptr = helpstring;
|
||||||
|
snprintf(hptr, hlen, "Usage: %%s [args]\n\n\tWhere args are:\n");
|
||||||
|
// format of help: "Usage: progname [args]\n"
|
||||||
|
change_helpstring(helpstring);
|
||||||
|
// parse arguments
|
||||||
|
parseargs(&argc, &argv, cmdlnopts);
|
||||||
|
if(help) showhelp(-1, cmdlnopts);
|
||||||
|
if(argc > 0){
|
||||||
|
G.rest_pars_num = argc;
|
||||||
|
G.rest_pars = MALLOC(char *, argc);
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
G.rest_pars[i] = strdup(argv[i]);
|
||||||
|
}
|
||||||
|
return &G;
|
||||||
|
}
|
||||||
|
|
||||||
|
// array with all opened logs - for error/warning messages
|
||||||
|
static Cl_log *errlogs = NULL;
|
||||||
|
static int errlogsnum = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cl_createlog - create log file: init mutex, test file open ability
|
||||||
|
* @param log - log structure
|
||||||
|
* @return 0 if all OK
|
||||||
|
*/
|
||||||
|
int Cl_createlog(Cl_log *log){
|
||||||
|
if(!log || !log->logpath || log->loglevel >= LOGLEVEL_NONE) return 1;
|
||||||
|
FILE *logfd = fopen(log->logpath, "a");
|
||||||
|
if(!logfd){
|
||||||
|
WARN("Can't open log file");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
fclose(logfd);
|
||||||
|
if(pthread_mutex_init(&log->mutex, NULL)){
|
||||||
|
WARN("Can't init log mutes");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
errlogs = realloc(errlogs, (++errlogsnum) *sizeof(Cl_log));
|
||||||
|
if(!errlogs) errlogsnum = 0;
|
||||||
|
else memcpy(&errlogs[errlogsnum-1], log, sizeof(Cl_log));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cl_putlog - put message to log file with/without timestamp
|
||||||
|
* @param timest - ==1 to put timestamp
|
||||||
|
* @param log - pointer to log structure
|
||||||
|
* @param lvl - message loglevel (if lvl > loglevel, message won't be printed)
|
||||||
|
* @param fmt - format and the rest part of message
|
||||||
|
* @return amount of symbols saved in file
|
||||||
|
*/
|
||||||
|
int Cl_putlogt(int timest, Cl_log *log, Cl_loglevel lvl, const char *fmt, ...){
|
||||||
|
if(!log || !log->logpath || log->loglevel >= LOGLEVEL_NONE) return 0;
|
||||||
|
if(lvl > log->loglevel) return 0;
|
||||||
|
if(pthread_mutex_lock(&log->mutex)){
|
||||||
|
WARN("Can't lock log mutex");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
FILE *logfd = fopen(log->logpath, "a");
|
||||||
|
if(!logfd) goto rtn;
|
||||||
|
if(timest){
|
||||||
|
char strtm[128];
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm *curtm = localtime(&t);
|
||||||
|
strftime(strtm, 128, "%Y/%m/%d-%H:%M", curtm);
|
||||||
|
i = fprintf(logfd, "%s\t", strtm);
|
||||||
|
}
|
||||||
|
va_list ar;
|
||||||
|
va_start(ar, fmt);
|
||||||
|
i += vfprintf(logfd, fmt, ar);
|
||||||
|
va_end(ar);
|
||||||
|
fclose(logfd);
|
||||||
|
rtn:
|
||||||
|
pthread_mutex_unlock(&log->mutex);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
69
NES_webiface/cmdlnopts.h
Normal file
69
NES_webiface/cmdlnopts.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the NES_web project.
|
||||||
|
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef CMDLNOPTS_H__
|
||||||
|
#define CMDLNOPTS_H__
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* here are some typedef's for global data
|
||||||
|
*/
|
||||||
|
typedef struct{
|
||||||
|
int vacuum; // make "vacuum" operation
|
||||||
|
int dumpUserDB; // dump users database
|
||||||
|
int dumpSessDB; // dump session database
|
||||||
|
int runServer; // run as server
|
||||||
|
int useradd; // add user[s]
|
||||||
|
char *port; // server port to listen
|
||||||
|
char *wsport; // websocket port to listen (!= port !!!)
|
||||||
|
char *certfile; // file with SSL certificate
|
||||||
|
char *keyfile; // file with SSL key
|
||||||
|
char *usersdb; // users database name
|
||||||
|
char *sessiondb; // session database name
|
||||||
|
char **userdel; // user names to delete
|
||||||
|
long long delatime; // minimal atime to delete sessions from DB
|
||||||
|
char *delsession; // delete session by sessID or sockID
|
||||||
|
char *logfilename; // name of log file
|
||||||
|
int rest_pars_num; // number of rest parameters
|
||||||
|
char** rest_pars; // the rest parameters: array of char*
|
||||||
|
} glob_pars;
|
||||||
|
|
||||||
|
extern glob_pars G;
|
||||||
|
|
||||||
|
glob_pars *parse_args(int argc, char **argv);
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
LOGLEVEL_DBG, // all messages
|
||||||
|
LOGLEVEL_MSG, // all without debug
|
||||||
|
LOGLEVEL_WARN, // only warnings and errors
|
||||||
|
LOGLEVEL_ERR, // only errors
|
||||||
|
LOGLEVEL_NONE // no logs
|
||||||
|
} Cl_loglevel;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
char *logpath; // full path to logfile
|
||||||
|
Cl_loglevel loglevel; // loglevel
|
||||||
|
pthread_mutex_t mutex; // log mutex
|
||||||
|
} Cl_log;
|
||||||
|
|
||||||
|
int Cl_createlog(Cl_log *log);
|
||||||
|
int Cl_putlogt(int timest, Cl_log *log, Cl_loglevel lvl, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif // CMDLNOPTS_H__
|
||||||
250
NES_webiface/main.c
Normal file
250
NES_webiface/main.c
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the NES_web project.
|
||||||
|
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <crypt.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <onion/block.h>
|
||||||
|
#include <onion/exportlocal.h>
|
||||||
|
#include <onion/handler.h>
|
||||||
|
#include <onion/log.h>
|
||||||
|
#include <onion/onion.h>
|
||||||
|
#include <onion/shortcuts.h>
|
||||||
|
#include <onion/types_internal.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "auth.h"
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "websockets.h"
|
||||||
|
|
||||||
|
// temporary
|
||||||
|
#define putlog(...)
|
||||||
|
|
||||||
|
onion_connection_status get(_U_ onion_handler *h, onion_request *req, onion_response *res){
|
||||||
|
sessinfo *session = qookieSession(req);
|
||||||
|
if(!session){
|
||||||
|
onion_response_write0(res, "NeedAuth");
|
||||||
|
ONION_WARNING("try to run command without auth");
|
||||||
|
return OCS_FORBIDDEN;
|
||||||
|
}
|
||||||
|
const char *path = onion_request_get_path(req);
|
||||||
|
if(path && *path == 0) path = NULL;
|
||||||
|
else printf("GET ask path %s\n", path);
|
||||||
|
const char *param = getQdata(req, "param");
|
||||||
|
if(param) printf("User set param=%s\n", param);
|
||||||
|
if(getQdata(req, "getWSkey")){
|
||||||
|
addWSkey(res, session);
|
||||||
|
}
|
||||||
|
freeSessInfo(&session);
|
||||||
|
return OCS_CLOSE_CONNECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static onion *os = NULL, *ow = NULL;
|
||||||
|
void signals(int signo){
|
||||||
|
closeSQLite();
|
||||||
|
if(os) onion_free(os);
|
||||||
|
if(ow) onion_free(ow);
|
||||||
|
exit(signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST/GET server
|
||||||
|
static void *runPostGet(_U_ void *data){
|
||||||
|
os = onion_new(O_THREADED);
|
||||||
|
if(!(onion_flags(os) & O_SSL_AVAILABLE)){
|
||||||
|
ONION_ERROR("SSL support is not available");
|
||||||
|
signals(1);
|
||||||
|
}
|
||||||
|
int error = onion_set_certificate(os, O_SSL_CERTIFICATE_KEY, G.certfile, G.keyfile);
|
||||||
|
if(error){
|
||||||
|
ONION_ERROR("Cant set certificate and key files (%s, %s)", G.certfile, G.keyfile);
|
||||||
|
signals(1);
|
||||||
|
}
|
||||||
|
onion_set_port(os, G.port);
|
||||||
|
onion_url *url = onion_root_url(os);
|
||||||
|
onion_url_add_handler(url, "^static/", onion_handler_export_local_new("static"));
|
||||||
|
onion_url_add_with_data(url, "", onion_shortcut_internal_redirect, "static/index.html", NULL);
|
||||||
|
onion_url_add(url, "^auth/", auth);
|
||||||
|
onion_url_add(url, "^get/", get);
|
||||||
|
error = onion_listen(os);
|
||||||
|
if(error) ONION_ERROR("Cant create POST/GET server: %s", strerror(errno));
|
||||||
|
onion_free(os);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Websocket server
|
||||||
|
static void *runWS(_U_ void *data){
|
||||||
|
ow = onion_new(O_THREADED);
|
||||||
|
if(!(onion_flags(ow) & O_SSL_AVAILABLE)){
|
||||||
|
ONION_ERROR("SSL support is not available");
|
||||||
|
signals(1);
|
||||||
|
}
|
||||||
|
int error = onion_set_certificate(ow, O_SSL_CERTIFICATE_KEY, G.certfile, G.keyfile);
|
||||||
|
if(error){
|
||||||
|
ONION_ERROR("Cant set certificate and key files (%s, %s)", G.certfile, G.keyfile);
|
||||||
|
signals(1);
|
||||||
|
}
|
||||||
|
onion_set_port(ow, G.wsport);
|
||||||
|
onion_url *url = onion_root_url(ow);
|
||||||
|
onion_url_add(url, "", websocket_run);
|
||||||
|
DBG("Listen websocket");
|
||||||
|
error = onion_listen(ow);
|
||||||
|
if(error) ONION_ERROR("Cant create POST/GET server: %s", strerror(errno));
|
||||||
|
onion_free(ow);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void runServer(){
|
||||||
|
// if(G.logfilename) Cl_createlog();
|
||||||
|
signal(SIGTERM, signals);
|
||||||
|
signal(SIGINT, signals);
|
||||||
|
signal(SIGQUIT, signals);
|
||||||
|
signal(SIGTSTP, SIG_IGN);
|
||||||
|
signal(SIGHUP, SIG_IGN);
|
||||||
|
|
||||||
|
pthread_t pg_thread, ws_thread;
|
||||||
|
if(pthread_create(&pg_thread, NULL, runPostGet, NULL)){
|
||||||
|
ERR("pthread_create()");
|
||||||
|
}
|
||||||
|
if(pthread_create(&ws_thread, NULL, runWS, NULL)){
|
||||||
|
ERR("pthread_create()");
|
||||||
|
}
|
||||||
|
do{
|
||||||
|
if(pthread_kill(pg_thread, 0) == ESRCH){ // POST/GET died
|
||||||
|
WARNX("POST/GET server thread died");
|
||||||
|
putlog("POST/GET server thread died");
|
||||||
|
pthread_join(pg_thread, NULL);
|
||||||
|
if(pthread_create(&pg_thread, NULL, runPostGet, NULL)){
|
||||||
|
putlog("pthread_create() failed");
|
||||||
|
ERR("pthread_create()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((pthread_kill(pg_thread, 0) == ESRCH) || (pthread_kill(ws_thread, 0) == ESRCH)){ // died
|
||||||
|
WARNX("Websocket server thread died");
|
||||||
|
putlog("Websocket server thread died");
|
||||||
|
pthread_join(ws_thread, NULL);
|
||||||
|
if(pthread_create(&ws_thread, NULL, runWS, NULL)){
|
||||||
|
putlog("pthread_create() failed");
|
||||||
|
ERR("pthread_create()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
usleep(1000); // sleep a little or thread's won't be able to lock mutex
|
||||||
|
if(dtime() - tgot < T_INTERVAL) continue;
|
||||||
|
tgot = dtime();
|
||||||
|
/*
|
||||||
|
* INSERT CODE HERE
|
||||||
|
* Gather data (poll_device)
|
||||||
|
*/
|
||||||
|
// copy temporary buffers to main
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
/*
|
||||||
|
* INSERT CODE HERE
|
||||||
|
* fill global data buffers
|
||||||
|
*/
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
#endif
|
||||||
|
}while(1);
|
||||||
|
putlog("Unreaceable code reached!");
|
||||||
|
ERRX("Unreaceable code reached!");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *getl(char *msg, int noempty){
|
||||||
|
static char *inpstr = NULL;
|
||||||
|
do{
|
||||||
|
FREE(inpstr);
|
||||||
|
printf("Enter %s: ", msg);
|
||||||
|
size_t n = 0;
|
||||||
|
if(getline(&inpstr, &n, stdin) < 0) FREE(inpstr);
|
||||||
|
else{
|
||||||
|
char *nl = strchr(inpstr, '\n');
|
||||||
|
if(nl) *nl = 0;
|
||||||
|
if(strlen(inpstr) < 1 && noempty){
|
||||||
|
WARNX("Enter non-empty string");
|
||||||
|
}else break;
|
||||||
|
}
|
||||||
|
}while(1);
|
||||||
|
return inpstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adduser(){
|
||||||
|
userinfo *User = MALLOC(userinfo, 1);
|
||||||
|
char *str;
|
||||||
|
do{
|
||||||
|
str = getl("username", 1);
|
||||||
|
printf("Username: %s\n", str);
|
||||||
|
User->username = strdup(str);
|
||||||
|
do{
|
||||||
|
str = getl("password", 1);
|
||||||
|
if(strlen(str) < 4){
|
||||||
|
WARNX("Bad password: not less than 4 symbols");
|
||||||
|
}else break;
|
||||||
|
}while(1);
|
||||||
|
User->password = strdup(crypt(str, "$6$"));
|
||||||
|
printf("PassHash: %s\n", User->password);
|
||||||
|
str = getl("access level", 1);
|
||||||
|
User->level = atoi(str);
|
||||||
|
printf("Level: %d\n", User->level);
|
||||||
|
str = getl("comment", 0);
|
||||||
|
if(strlen(str)){
|
||||||
|
User->comment = strdup(str);
|
||||||
|
printf("Comment: %s", User->comment);
|
||||||
|
}
|
||||||
|
if(addUser(User)) continue;
|
||||||
|
if(!(str = getl("next? (y/n)", 0)) || 0 != strcmp(str, "y")) break;
|
||||||
|
}while(1);
|
||||||
|
freeUserInfo(&User);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern char *onion_sessions_generate_id();
|
||||||
|
|
||||||
|
int main(int argc, char **argv){
|
||||||
|
initial_setup();
|
||||||
|
parse_args(argc, argv);
|
||||||
|
if(!G.usersdb) ERRX("You should point users database file name");
|
||||||
|
if(!G.sessiondb) ERRX("You should point session database file name");
|
||||||
|
if(initSQLite(G.usersdb, G.sessiondb)) return 1;
|
||||||
|
if(G.vacuum){
|
||||||
|
printf("VAAAA\n");
|
||||||
|
vacuumSQLite();
|
||||||
|
}
|
||||||
|
if(G.dumpUserDB) showAllUsers();
|
||||||
|
if(G.userdel){
|
||||||
|
for(int i = 0; G.userdel[i]; ++i){
|
||||||
|
if(!deleteUser(G.userdel[i])) green("User %s deleted\n", G.userdel[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(G.useradd) adduser();
|
||||||
|
if(G.dumpSessDB) showAllSessions();
|
||||||
|
if(G.delsession){
|
||||||
|
if(!deleteSession(G.delsession))
|
||||||
|
green("Session with ID %s deleted\n", G.delsession);
|
||||||
|
}
|
||||||
|
if(G.delatime){
|
||||||
|
if(G.delatime < 0) G.delatime = time(NULL) - 31556926LL;
|
||||||
|
if(!deleteOldSessions((int64_t)G.delatime))
|
||||||
|
green("All sessions with atime<%lld deleted\n", G.delatime);
|
||||||
|
}
|
||||||
|
if(G.runServer){
|
||||||
|
if(strcmp(G.port, G.wsport) == 0) ERRX("Server port ans websocket port should be different!");
|
||||||
|
runServer();
|
||||||
|
}
|
||||||
|
closeSQLite();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
156
NES_webiface/static/admin.html
Normal file
156
NES_webiface/static/admin.html
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style type="text/css">
|
||||||
|
.shadow{
|
||||||
|
display:none;
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
}
|
||||||
|
.midmsg{
|
||||||
|
position:fixed;
|
||||||
|
top:50%;
|
||||||
|
left:50%;
|
||||||
|
margin-left:auto;
|
||||||
|
margin-right:auto;
|
||||||
|
}
|
||||||
|
.C{text-align:center;}
|
||||||
|
.R{text-align:right;}
|
||||||
|
</style>
|
||||||
|
<script src="/pass.js" type="text/javascript" language="javascript"></script>
|
||||||
|
<script>
|
||||||
|
var user="", passwd="", level="", url="";
|
||||||
|
const CGI_PATH = "https://ishtar.sao.ru/cgi-bin/auth";
|
||||||
|
function parseErr(txt){
|
||||||
|
$('msg').innerHTML = "ïÛÉÂËÁ!<p></p>" + txt.replace("\n", "<br>");
|
||||||
|
setTimeout(function(){$('msg').innerHTML = "";}, 3500);
|
||||||
|
}
|
||||||
|
function sendrequest(request, req_STR, onOK){
|
||||||
|
var timeout_id
|
||||||
|
request = new XMLHttpRequest();
|
||||||
|
request.open("POST", CGI_PATH, true);
|
||||||
|
request.setRequestHeader("Accept-Charset", "koi8-r");
|
||||||
|
request.overrideMimeType("multipart/form-data; charset=koi8-r");
|
||||||
|
request.setRequestHeader("Cookie", document.cookie);
|
||||||
|
request.onreadystatechange=function(){
|
||||||
|
if (request.readyState == 4){
|
||||||
|
if (request.status == 200){
|
||||||
|
clearTimeout(timeout_id);
|
||||||
|
onOK(request);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
clearTimeout(timeout_id);
|
||||||
|
parseErr("ïÛÉÂËÁ ÐÅÒÅÄÁÞÉ ÚÁÐÒÏÓÁ. ðÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.send(req_STR);
|
||||||
|
timeout_id = setTimeout(function(){parseErr("ôÁÊÍÁÕÔ ÐÅÒÅÄÁÞÉ ÚÁÐÒÏÓÁ. ðÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ.");}, 3000);
|
||||||
|
}
|
||||||
|
function run(){
|
||||||
|
var QS;
|
||||||
|
sendrequest(QS, "admin=lsusers", lsusers);
|
||||||
|
}
|
||||||
|
function lsusers(QS){
|
||||||
|
var ans = QS.responseText;
|
||||||
|
var pars = ans.split("\n");
|
||||||
|
var i, l, s;
|
||||||
|
for(i=0, l=pars.length; i < l; i++){
|
||||||
|
s = pars[i].split(";");
|
||||||
|
if(pars[i].length < 2) continue;
|
||||||
|
if(s.length != 3){
|
||||||
|
parseErr(ans+"<br>str="+s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addUsersString(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function addUsersString(str){
|
||||||
|
var ulist = $('userlist');
|
||||||
|
var div = document.createElement('div');
|
||||||
|
ulist.appendChild(div);
|
||||||
|
var u = str[0];
|
||||||
|
div.innerHTML = "<span>"+u+"</span> <span>"+str[1]+"</span> <span>"+str[2]+"</span> "+
|
||||||
|
"<span onclick='delUser(\""+u+"\");'>delete</span> "+
|
||||||
|
"<span onclick='editUser(\""+u+"\",\""+str[1]+"\",\""+str[2]+"\");'>edit</span>";
|
||||||
|
}
|
||||||
|
function useradd(arg){
|
||||||
|
function pair(name){
|
||||||
|
var str = "<div class='R'>"+name+"<input type=text id="+
|
||||||
|
name+" onchange=\""+name+"=$('"+name+"').value;\""+
|
||||||
|
" onblur=\""+name+"=$('"+name+"').value;\" value='"+eval(name)+"'></div>"
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
var div = document.createElement('div');
|
||||||
|
$("box").style.display = "block";
|
||||||
|
div.className = "midmsg";
|
||||||
|
$("box").appendChild(div);
|
||||||
|
div.innerHTML = "<div class='C'>äÏÂÁ×ÉÔØ/ÉÚÍÅÎÉÔØ ÐÏÌØÚÏ×ÁÔÅÌÑ</div>"+
|
||||||
|
pair("user")+pair("passwd")+pair("level")+pair("url")+
|
||||||
|
"<div class='C'><button onclick='addUser(\""+arg+"\");'>OK</button>"+
|
||||||
|
"<button onclick='cancelAdd();'>ïÔÍÅÎÁ</button></div>";
|
||||||
|
}
|
||||||
|
function chkAns(req, Msg){
|
||||||
|
if(req.responseText.length > 0)
|
||||||
|
parseErr(Msg);
|
||||||
|
else{
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function addUser(arg){
|
||||||
|
var request;
|
||||||
|
function cantadd(req){
|
||||||
|
chkAns(req, "ÎÅ ÍÏÇÕ ÄÏÂÁ×ÉÔØ/ÒÅÄÁËÔÉÒÏ×ÁÔØ ÐÏÌØÚÏ×ÁÔÅÌÑ<br>"+req.responseText);
|
||||||
|
}
|
||||||
|
if(user==""){
|
||||||
|
parseErr("ïÔÓÕÔÓÔ×ÕÅÔ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(passwd==""){
|
||||||
|
parseErr("îÅ ÚÁÄÁÎ ÐÁÒÏÌØ ÐÏÌØÚÏ×ÁÔÅÌÑ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(level=="" || Number(level) < 0){
|
||||||
|
parseErr("îÅ ÚÁÄÁÎ ÉÌÉ ÚÁÄÁÎ ÎÅ×ÅÒÎÏ ÕÒÏ×ÅÎØ ÄÏÓÔÕÐÁ ÐÏÌØÚÏ×ÁÔÅÌÑ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(url==""){
|
||||||
|
parseErr("îÅ ÚÁÄÁÎ ÁÄÒÅÓ ÄÏÓÔÕÐÎÙÈ ÐÏÌØÚÏ×ÁÔÅÌÀ ÒÅÓÕÒÓÏ× (ÉÌÉ \"/\", ÅÓÌÉ ÄÏÓÔÕÐÎÏ ×ÓÅ)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendrequest(request,
|
||||||
|
"admin="+arg+"&user="+user+"&passwd="+passwd+"&level="+level+"&URL="+url,
|
||||||
|
cantadd);
|
||||||
|
user = passwd = level = url = "";
|
||||||
|
}
|
||||||
|
function cancelAdd(){
|
||||||
|
user = passwd = level = url = "";
|
||||||
|
$("box").innerHTML = "";
|
||||||
|
$("box").style.display = "none";
|
||||||
|
}
|
||||||
|
function delUser(username){
|
||||||
|
var request;
|
||||||
|
function cantdel(req){
|
||||||
|
chkAns(req, "ÎÅ ÍÏÇÕ ÕÄÁÌÉÔØ ÐÏÌØÚÏ×ÁÔÅÌÑ<br>"+req.responseText);
|
||||||
|
}
|
||||||
|
sendrequest(request, "admin=userdel&user="+username, cantdel);
|
||||||
|
}
|
||||||
|
function editUser(username, ulevl, uurl){
|
||||||
|
user = username; passwd = "";
|
||||||
|
level = ulevl; url = uurl;
|
||||||
|
useradd("usermod");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<title>õÐÒÁ×ÌÅÎÉÅ ÐÏÌØÚÏ×ÁÔÅÌÑÍÉ</title>
|
||||||
|
</head>
|
||||||
|
<body onload="getcookie(CGI_PATH); run();">
|
||||||
|
<div class="shadow" id="box"></div>
|
||||||
|
<div id="inout" style="position: fixed; top: 10px; right: 10px; cursor: pointer; font-weight: bold;" onclick="inout();" >÷ÈÏÄ</div>
|
||||||
|
<div onclick="useradd('useradd');">îÏ×ÙÊ ÐÏÌØÚÏ×ÁÔÅÌØ</div>
|
||||||
|
<div id="userlist"></div>
|
||||||
|
|
||||||
|
<div id="msg" style="margin-top: 15px; color: red;"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
96
NES_webiface/static/auth.js
Normal file
96
NES_webiface/static/auth.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
auth = function(){
|
||||||
|
var wsKey = "";
|
||||||
|
function _ilogin(){
|
||||||
|
$("inout").innerHTML = "Log in";
|
||||||
|
$("inout").onclick = auth.login;
|
||||||
|
}
|
||||||
|
function _ilogout(){
|
||||||
|
$("shadow").style.display = "none";
|
||||||
|
$("inout").innerHTML = "Log out";
|
||||||
|
$("inout").onclick = auth.logout;
|
||||||
|
}
|
||||||
|
function _wsk(request){
|
||||||
|
wsKey = request.responseText;
|
||||||
|
if(wsKey) console.log("Web key received: " + wsKey);
|
||||||
|
wsinit();
|
||||||
|
}
|
||||||
|
function reqAuth(request){
|
||||||
|
var txt = request.responseText;
|
||||||
|
dbg("received " + txt);
|
||||||
|
if(txt == "AuthOK"){ // cookies received
|
||||||
|
sendrequest("get/?getWSkey", _wsk);
|
||||||
|
_ilogout();
|
||||||
|
}else if(txt == "NeedAuth"){
|
||||||
|
_ilogin();
|
||||||
|
}else{
|
||||||
|
parseErr(txt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function init1(){
|
||||||
|
sendrequest("auth/?check=1", reqAuth);
|
||||||
|
var l = document.createElement('a');
|
||||||
|
l.id = "inout";
|
||||||
|
l.href = "#";
|
||||||
|
var s1 = document.createElement('style');
|
||||||
|
s1.type = 'text/css';
|
||||||
|
s1.innerHTML = ".inout{position:absolute;top:0;right:0;background-color:green;"
|
||||||
|
document.body.appendChild(s1);
|
||||||
|
l.className = "inout";
|
||||||
|
document.body.appendChild(l);
|
||||||
|
var d = document.createElement('div');
|
||||||
|
d.id = "shadow";
|
||||||
|
var s = document.createElement('style');
|
||||||
|
s.type = 'text/css';
|
||||||
|
s.innerHTML = '.shadow{position:absolute;text-align:center;vertical-align:center;top:0;display:none;left:0;width:100%;height:100%;background-color:lightGrey;opacity:0.9;}';
|
||||||
|
document.body.appendChild(s);
|
||||||
|
d.innerHTML = "<div>Login:</div><div><input type=text id='login'></div><div>Password:</div><div><input type=password id='passwd'></div><button onclick='auth.send();'>OK</button>";
|
||||||
|
d.className = "shadow";
|
||||||
|
document.body.appendChild(d);
|
||||||
|
}
|
||||||
|
function login1(){
|
||||||
|
$("shadow").style.display = "block";
|
||||||
|
}
|
||||||
|
function logout1(){
|
||||||
|
sendrequest("auth/?LogOut=1", _ilogin);
|
||||||
|
}
|
||||||
|
function sendlogpass(){
|
||||||
|
$("shadow").style.display = "none";
|
||||||
|
var l = $("login").value, p = $("passwd").value;
|
||||||
|
if(!l || !p){
|
||||||
|
parseErr("give login and password");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var str = "auth/?login=" + l + "&passwd=" + p;
|
||||||
|
sendrequest(str, reqAuth);
|
||||||
|
}
|
||||||
|
// websockets
|
||||||
|
var ws;
|
||||||
|
function wsinit(){
|
||||||
|
delete(ws);
|
||||||
|
ws = new WebSocket('wss://localhost:8081');
|
||||||
|
ws.onopen = function(){ws.send("Akey="+wsKey);}; // send key after init
|
||||||
|
ws.onclose = function(evt){
|
||||||
|
var text = "WebSocket closed: ";
|
||||||
|
if(evt.wasClean) text += "by remote side";
|
||||||
|
else text += "connection lost"
|
||||||
|
$('wsmsgs').innerHTML = text;
|
||||||
|
};
|
||||||
|
ws.onmessage = function(evt){
|
||||||
|
$('wsmsgs').innerHTML = evt.data;
|
||||||
|
}
|
||||||
|
ws.onerror = function(err){
|
||||||
|
parseErr("WebSocket error " + err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function wssend(txt){
|
||||||
|
ws.send(txt);
|
||||||
|
}
|
||||||
|
return{
|
||||||
|
init: init1,
|
||||||
|
login: login1,
|
||||||
|
logout: logout1,
|
||||||
|
send: sendlogpass,
|
||||||
|
wssend: wssend,
|
||||||
|
wsinit: wsinit
|
||||||
|
};
|
||||||
|
}();
|
||||||
16
NES_webiface/static/index.html
Normal file
16
NES_webiface/static/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Index</title>
|
||||||
|
<script src="/static/requests.js" type="text/javascript" language="javascript"></script>
|
||||||
|
<script src="/static/auth.js" type="text/javascript" language="javascript"></script>
|
||||||
|
</head>
|
||||||
|
<body onload="auth.init();">
|
||||||
|
<p>Text
|
||||||
|
<p>More text
|
||||||
|
<p>
|
||||||
|
<div id="wsmsgs"></div>
|
||||||
|
<div id="errmsg" style='background-color: red;'></div>
|
||||||
|
<p>
|
||||||
|
<input type="text" id="wssnd" onchange="auth.wssend($('wssnd').value);">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
92
NES_webiface/static/pass.html
Normal file
92
NES_webiface/static/pass.html
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>á×ÔÏÒÉÚÁÃÉÑ</title>
|
||||||
|
<script>
|
||||||
|
const CGI_PATH = "https://ishtar.sao.ru/cgi-bin/auth";
|
||||||
|
var URL=new Array(), RTN=null, reqnmbr=0;
|
||||||
|
function $(id){ return document.getElementById(id);}
|
||||||
|
function getargs(){
|
||||||
|
var QS = window.location.search.substring(1);
|
||||||
|
var pars = QS.split("&");
|
||||||
|
var i=0, s;
|
||||||
|
while((s=pars[i++])){
|
||||||
|
if(s.indexOf('URL') == 0){
|
||||||
|
s = s.split('=');
|
||||||
|
URL[URL.length] = s[1];
|
||||||
|
}
|
||||||
|
else if(s.indexOf('RTN') == 0){
|
||||||
|
s = s.split('=');
|
||||||
|
RTN = s[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(URL.length == 0){alert("ïÔÓÕÔÓÔ×ÕÅÔ URL ÄÌÑ Á×ÔÏÒÉÚÁÃÉÉ"); return;}
|
||||||
|
if(RTN == null) RTN = URL[0];
|
||||||
|
}
|
||||||
|
function sendrequest(req_STR, onOK){
|
||||||
|
var request = new XMLHttpRequest(), timeout_id;
|
||||||
|
request.open("POST", CGI_PATH, true);
|
||||||
|
request.setRequestHeader("Accept-Charset", "koi8-r");
|
||||||
|
request.overrideMimeType("multipart/form-data; charset=koi8-r");
|
||||||
|
request.onreadystatechange=function(){
|
||||||
|
if (request.readyState == 4){
|
||||||
|
if (request.status == 200){
|
||||||
|
clearTimeout(timeout_id);
|
||||||
|
if(onOK) onOK(request);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
clearTimeout(timeout_id);
|
||||||
|
parseErr("request sending error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.send(req_STR);
|
||||||
|
timeout_id = setTimeout(function(){request.onreadystatechange=null; request.abort(); parseErr("request timeout");}, 3000);
|
||||||
|
}
|
||||||
|
function subm(id){
|
||||||
|
var str, str1, i;
|
||||||
|
var login = $('login').value;
|
||||||
|
var pass = $('passwd').value;
|
||||||
|
if(login == "" || pass == ""){
|
||||||
|
if(id) $(id).focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var str = "login=" + login + " passwd=" + pass;
|
||||||
|
for(i = 0; i < URL.length; i++){
|
||||||
|
str1 = str + " URL=" + URL[i];
|
||||||
|
sendrequest(str1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onOK(request){
|
||||||
|
var txt = request.responseText;
|
||||||
|
if(txt.indexOf("KEY") != 0){
|
||||||
|
parseErr(txt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var n = txt.indexOf('\n');
|
||||||
|
if(n) txt = txt.substring(0, n);
|
||||||
|
var d = new Date();
|
||||||
|
d.setTime(d.getTime() + 72e6); // ÓÒÏË ÄÅÊÓÔ×ÉÑ ËÕËÉ - 20 ÞÁÓÏ×
|
||||||
|
txt += "; expires="+d.toGMTString();
|
||||||
|
document.cookie = txt;
|
||||||
|
if(++reqnmbr == URL.length) document.location.href = RTN;
|
||||||
|
}
|
||||||
|
function parseErr(txt){
|
||||||
|
console.log("Error: " + txt);
|
||||||
|
$('msg').innerHTML = "Error: " + txt;
|
||||||
|
setTimeout(function(){$('msg').innerHTML = "";}, 3500);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="getargs();">
|
||||||
|
<div align="center">
|
||||||
|
<h2>ðÏÖÁÌÕÊÓÔÁ ××ÅÄÉÔÅ ÒÅÇÉÓÔÒÁÃÉÏÎÎÕÀ ÉÎÆÏÒÍÁÃÉÀ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÄÏÓÔÕÐÁ Ë ÓÅÒ×ÉÓÁÍ</h2>
|
||||||
|
<div style="border: 1px solid; text-align: center; width: 200px; margin: 0 auto; padding: 5px;" id="pass">
|
||||||
|
<div>éÍÑ:</div><div><input type=text id="login" onchange="subm('passwd');"></div>
|
||||||
|
<div>ðÁÒÏÌØ:</div><div><input type=password id="passwd" onchange="subm('login');"></div><br>
|
||||||
|
<div align=center><button onclick="subm();">OK</button></div>
|
||||||
|
</div>
|
||||||
|
<div id="msg" style="margin-top: 15px; color: red;"></div>
|
||||||
|
</div>
|
||||||
|
<body>
|
||||||
|
</html>
|
||||||
56
NES_webiface/static/pass.js
Normal file
56
NES_webiface/static/pass.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// move this file to the root html directory
|
||||||
|
// change const's EXURL & PASSURL
|
||||||
|
var KEY;
|
||||||
|
const PASSURL="https://ishtar.sao.ru/pass";
|
||||||
|
const EXURL = "https://ishtar.sao.ru/cgi-bin/auth";
|
||||||
|
function $(id){
|
||||||
|
return document.getElementById(id);
|
||||||
|
}
|
||||||
|
function checkcookie(){
|
||||||
|
var txt = document.cookie;
|
||||||
|
if(txt.length==0 || txt.indexOf('KEY')<0){
|
||||||
|
$("inout").innerHTML = "÷ÏÊÔÉ";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$("inout").innerHTML = "÷ÙÊÔÉ";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getcookie(){
|
||||||
|
/* ÂÅÚ ÁÒÇÕÍÅÎÔÏ× - ÄÌÑ ÔÅËÕÝÅÊ ÓÔÒÁÎÉÃÙ,
|
||||||
|
ËÁÖÄÙÊ ÁÒÇÕÍÅÎÔ - ÄÏÐ. "ÐÅÞÅÎØËÁ"
|
||||||
|
*/
|
||||||
|
var i, newurl = PASSURL+"?URL="+document.location.href;
|
||||||
|
for(i = 0; i < getcookie.arguments.length; i++)
|
||||||
|
newurl += "&URL=" + getcookie.arguments[i];
|
||||||
|
if(!checkcookie())
|
||||||
|
document.location.href = newurl;
|
||||||
|
}
|
||||||
|
function onEX(){
|
||||||
|
var d = new Date();
|
||||||
|
d.setTime(d.getTime() - 1000);
|
||||||
|
var str = "KEY=; expires="+d.toGMTString()+"; path="+document.location.pathname;
|
||||||
|
document.cookie = str;
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
function exit(){
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open("POST", EXURL, true);
|
||||||
|
request.setRequestHeader("Accept-Charset", "koi8-r");
|
||||||
|
request.setRequestHeader("Cookie", document.cookie);
|
||||||
|
request.overrideMimeType("multipart/form-data; charset=koi8-r");
|
||||||
|
request.onreadystatechange=function(){
|
||||||
|
if (request.readyState == 4){
|
||||||
|
if (request.status == 200){
|
||||||
|
onEX();
|
||||||
|
}
|
||||||
|
else alert("ïÛÉÂËÁ ÓÏÅÄÉÎÅÎÉÑ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.send("")
|
||||||
|
}
|
||||||
|
function inout(){
|
||||||
|
if(checkcookie()) exit();
|
||||||
|
else getcookie();
|
||||||
|
}
|
||||||
43
NES_webiface/static/requests.js
Normal file
43
NES_webiface/static/requests.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const Debug = true;
|
||||||
|
|
||||||
|
var elementsCache = {};
|
||||||
|
function $(id) {
|
||||||
|
if (elementsCache[id] === undefined)
|
||||||
|
elementsCache[id] = document.getElementById(id);
|
||||||
|
return elementsCache[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function dbg(text){
|
||||||
|
if(Debug) console.log("Debug message: " + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendrequest(req_STR, onOK, postdata){
|
||||||
|
var request = new XMLHttpRequest(), timeout_id;
|
||||||
|
dbg("send request " + req_STR);
|
||||||
|
var method = postdata ? "POST" : "GET";
|
||||||
|
request.open(method, req_STR, true);
|
||||||
|
//request.setRequestHeader("Accept-Charset", "koi8-r");
|
||||||
|
//request.overrideMimeType("multipart/form-data; charset=koi8-r");
|
||||||
|
request.onreadystatechange=function(){
|
||||||
|
if(request.readyState == 4){
|
||||||
|
if(request.status == 200){
|
||||||
|
clearTimeout(timeout_id);
|
||||||
|
if(onOK) onOK(request);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
clearTimeout(timeout_id);
|
||||||
|
parseErr("request sending error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.send(postdata);
|
||||||
|
timeout_id = setTimeout(function(){request.onreadystatechange=null; request.abort(); parseErr("request timeout");}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseErr(txt){
|
||||||
|
console.log("Error: " + txt);
|
||||||
|
var msgDiv = $('errmsg');
|
||||||
|
if(!msgDiv) return;
|
||||||
|
msgDiv.innerHTML = "Error: " + txt;
|
||||||
|
setTimeout(function(){msgDiv.innerHTML = "";}, 3500);
|
||||||
|
}
|
||||||
88
NES_webiface/websockets.c
Normal file
88
NES_webiface/websockets.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the NES_web project.
|
||||||
|
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "auth.h"
|
||||||
|
#include "websockets.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <onion/log.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#define BUFLEN 255
|
||||||
|
|
||||||
|
// bit-fields of `data` field (websocket_cont)
|
||||||
|
#define WS_FLAG_NOTAUTHORIZED 1
|
||||||
|
|
||||||
|
static onion_connection_status websocket_cont(void *data, onion_websocket *ws, ssize_t dlen){
|
||||||
|
FNAME();
|
||||||
|
uint32_t flags = *((uint32_t*)data);
|
||||||
|
char tmp[BUFLEN+1];
|
||||||
|
if(dlen > BUFLEN) dlen = BUFLEN;
|
||||||
|
|
||||||
|
int len = onion_websocket_read(ws, tmp, dlen);
|
||||||
|
if(len <= 0){
|
||||||
|
ONION_ERROR("Error reading data: %d: %s (%d)", errno, strerror(errno), dlen);
|
||||||
|
return OCS_NEED_MORE_DATA;
|
||||||
|
}
|
||||||
|
tmp[len] = 0;
|
||||||
|
//ONION_INFO("Read from websocket: %s (len=%d)", tmp, len);
|
||||||
|
DBG("WS: got %s", tmp);
|
||||||
|
if(flags & WS_FLAG_NOTAUTHORIZED){ // not authorized over websocket
|
||||||
|
sessinfo *session = NULL;
|
||||||
|
if(strncmp(tmp, "Akey=", 5) == 0){ // got authorized key - check it
|
||||||
|
char *key = tmp + 5;
|
||||||
|
session = getSession(key);
|
||||||
|
/* here we should make a proper check, but for now do simplest */
|
||||||
|
}
|
||||||
|
if(!session){
|
||||||
|
onion_websocket_printf(ws, AUTH_ANS_NEEDAUTH);
|
||||||
|
WARNX("Wrong websocket session ID");
|
||||||
|
return OCS_FORBIDDEN;
|
||||||
|
}
|
||||||
|
flags &= ~WS_FLAG_NOTAUTHORIZED; // clear non-authorized flag
|
||||||
|
return OCS_NEED_MORE_DATA;
|
||||||
|
}
|
||||||
|
char *eq = strchr(tmp, '=');
|
||||||
|
if(eq){
|
||||||
|
*eq++ = 0;
|
||||||
|
onion_websocket_printf(ws, "parameter: '%s', its value: '%s'", tmp, eq);
|
||||||
|
}else{
|
||||||
|
onion_websocket_printf(ws, "Echo: %s", tmp);
|
||||||
|
}
|
||||||
|
return OCS_NEED_MORE_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
onion_connection_status websocket_run(_U_ void *data, onion_request *req, onion_response *res){
|
||||||
|
FNAME();
|
||||||
|
onion_websocket *ws = onion_websocket_new(req, res);
|
||||||
|
if (!ws){
|
||||||
|
green("PROC\n");
|
||||||
|
DBG("Processed");
|
||||||
|
return OCS_PROCESSED;
|
||||||
|
}
|
||||||
|
DBG("WS ready");
|
||||||
|
const char *host = onion_request_get_client_description(req);
|
||||||
|
const char *UA = onion_request_get_header(req, "User-Agent");
|
||||||
|
green("Got WS connection from %s (UA: %s)\n", host, UA);
|
||||||
|
uint32_t *flags = calloc(1, 4);
|
||||||
|
onion_websocket_set_userdata(ws, (void*)flags, free);
|
||||||
|
onion_websocket_set_callback(ws, websocket_cont);
|
||||||
|
return OCS_WEBSOCKET;
|
||||||
|
}
|
||||||
26
NES_webiface/websockets.h
Normal file
26
NES_webiface/websockets.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the NES_web project.
|
||||||
|
* Copyright 2020 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#ifndef WEBSOCKETS_H__
|
||||||
|
#define WEBSOCKETS_H__
|
||||||
|
#include <onion/onion.h>
|
||||||
|
#include <onion/websocket.h>
|
||||||
|
|
||||||
|
onion_connection_status websocket_run(void *data, onion_request *req, onion_response *res);
|
||||||
|
|
||||||
|
#endif // WEBSOCKETS_H__
|
||||||
6
README
6
README
@ -9,6 +9,8 @@ fifo_lifo - simple stack-like queues
|
|||||||
|
|
||||||
netdaemon - snippet for network management of serial devices
|
netdaemon - snippet for network management of serial devices
|
||||||
|
|
||||||
|
serialsock - socket server for serial devices
|
||||||
|
|
||||||
simple_list - 1-directional list with functions: add element; delete list
|
simple_list - 1-directional list with functions: add element; delete list
|
||||||
|
|
||||||
stellarium_emul - snippet for stellarium telescope remote control
|
stellarium_emul - snippet for stellarium telescope remote control
|
||||||
@ -23,3 +25,7 @@ usefull_macros - a lot of different macros & functions
|
|||||||
* MMAP files into memory
|
* MMAP files into memory
|
||||||
|
|
||||||
USBrelay - simplest tool to manage USB-HID chinese relays
|
USBrelay - simplest tool to manage USB-HID chinese relays
|
||||||
|
|
||||||
|
|
||||||
|
translate c into asm: gcc -S -fverbose-asm file.c
|
||||||
|
|
||||||
|
|||||||
1
Socket_CAN/99-socketcan.rules
Normal file
1
Socket_CAN/99-socketcan.rules
Normal file
@ -0,0 +1 @@
|
|||||||
|
SUBSYSTEMS=="net", ACTION=="add", ENV{INTERFACE}=="can0", RUN+="/etc/udev/rules.d/socketcan0"
|
||||||
5
Socket_CAN/HOWTO.cert
Normal file
5
Socket_CAN/HOWTO.cert
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
create:
|
||||||
|
openssl req -newkey rsa:2048 -nodes -keyout cert.key -x509 -days 10100 -out cert.pem
|
||||||
|
|
||||||
|
review:
|
||||||
|
openssl x509 -text -noout -in cert.pem
|
||||||
63
Socket_CAN/Makefile
Normal file
63
Socket_CAN/Makefile
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# run `make DEF=...` to add extra defines
|
||||||
|
CLIENT := soccanclient
|
||||||
|
SERVER := soccanserver
|
||||||
|
LDFLAGS += -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||||
|
LDFLAGS += -lusefull_macros -lssl -lcrypto
|
||||||
|
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
|
||||||
|
SOBJDIR := mkserver
|
||||||
|
COBJDIR := mkclient
|
||||||
|
CFLAGS += -O2 -Wno-trampolines -std=gnu99 -pthread
|
||||||
|
COMMSRCS := sslsock.c daemon.c cmdlnopts.c
|
||||||
|
SSRC := server.c can_io.c $(COMMSRCS)
|
||||||
|
CSRC := client.c $(COMMSRCS)
|
||||||
|
SOBJS := $(addprefix $(SOBJDIR)/, $(SSRC:%.c=%.o))
|
||||||
|
COBJS := $(addprefix $(COBJDIR)/, $(CSRC:%.c=%.o))
|
||||||
|
SDEPS := $(SOBJS:.o=.d)
|
||||||
|
CDEPS := $(COBJS:.o=.d)
|
||||||
|
CC = gcc
|
||||||
|
#CXX = g++
|
||||||
|
|
||||||
|
|
||||||
|
all : $(SOBJDIR) $(COBJDIR) $(CLIENT) $(SERVER)
|
||||||
|
|
||||||
|
debug: DEFINES += -DEBUG -Werror -Wall -Wextra
|
||||||
|
debug: all
|
||||||
|
|
||||||
|
$(CLIENT) : DEFINES += -DCLIENT
|
||||||
|
$(CLIENT) : $(COBJS)
|
||||||
|
@echo -e "\t\tLD $(CLIENT)"
|
||||||
|
$(CC) $(LDFLAGS) $(COBJS) -o $(CLIENT)
|
||||||
|
|
||||||
|
|
||||||
|
$(SERVER) : DEFINES += -DSERVER
|
||||||
|
$(SERVER) : $(SOBJS)
|
||||||
|
@echo -e "\t\tLD $(SERVER)"
|
||||||
|
$(CC) $(LDFLAGS) $(SOBJS) -o $(SERVER)
|
||||||
|
|
||||||
|
$(SOBJDIR):
|
||||||
|
mkdir $(SOBJDIR)
|
||||||
|
|
||||||
|
$(COBJDIR):
|
||||||
|
mkdir $(COBJDIR)
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(SDEPS) $(CDEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(SOBJDIR)/%.o: %.c
|
||||||
|
@echo -e "\t\tCC $<"
|
||||||
|
$(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $<
|
||||||
|
|
||||||
|
$(COBJDIR)/%.o: %.c
|
||||||
|
@echo -e "\t\tCC $<"
|
||||||
|
$(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo -e "\t\tCLEAN"
|
||||||
|
@rm -f $(SOBJS) $(SDEPS) $(COBJS) $(CDEPS) 2>/dev/null || true
|
||||||
|
@rmdir $(SOBJDIR) $(COBJDIR) 2>/dev/null || true
|
||||||
|
|
||||||
|
xclean: clean
|
||||||
|
@rm -f $(PROGRAM)
|
||||||
|
|
||||||
|
.PHONY: clean xclean
|
||||||
62
Socket_CAN/Makefile.bk
Normal file
62
Socket_CAN/Makefile.bk
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# run `make DEF=...` to add extra defines
|
||||||
|
CLIENT := soccanclient
|
||||||
|
SERVER := soccanserver
|
||||||
|
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||||
|
LDFLAGS += -lusefull_macros
|
||||||
|
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
|
||||||
|
OBJDIR := mk
|
||||||
|
CFLAGS += -O2 -Wno-trampolines -std=gnu99
|
||||||
|
SSRC := server.c
|
||||||
|
CSRC := client.c
|
||||||
|
COMMSRCS := sslsock.c daemon.c cmdlnopts.c
|
||||||
|
SOBJS := $(addprefix $(OBJDIR)/, $(SSRC:%.c=%.o))
|
||||||
|
COBJS := $(addprefix $(OBJDIR)/, $(CSRC:%.c=%.o))
|
||||||
|
COMMOBJS := $(addprefix $(OBJDIR)/, $(COMMSRCS:%.c=%.o))
|
||||||
|
OBJS := $(SOBJS) $(COBJS) $(COMMOBJS)
|
||||||
|
DEPS := $(OBJS:.o=.d)
|
||||||
|
CC = gcc
|
||||||
|
#CXX = g++
|
||||||
|
|
||||||
|
|
||||||
|
all : $(OBJDIR) $(CLIENT) $(SERVER)
|
||||||
|
|
||||||
|
debug: DEFINES += -DEBUG -Werror -Wall -Wextra
|
||||||
|
debug: all
|
||||||
|
|
||||||
|
$(CLIENT) : DEFINES += -DCLIENT
|
||||||
|
$(CLIENT) : $(COBJS)
|
||||||
|
@rm $(COMMOBJS) 2>/dev/null || true
|
||||||
|
@make DEF="$(DEFINES)" $(COMMOBJS)
|
||||||
|
@echo -e "\t\tLD $(CLIENT)"
|
||||||
|
$(CC) $(LDFLAGS) $(COBJS) $(COMMOBJS) -o $(CLIENT)
|
||||||
|
|
||||||
|
|
||||||
|
$(SERVER) : DEFINES += -DSERVER
|
||||||
|
$(SERVER) : $(SOBJS)
|
||||||
|
@rm $(COMMOBJS) 2>/dev/null || true
|
||||||
|
@make DEF="$(DEFINES)" $(COMMOBJS)
|
||||||
|
@echo -e "\t\tLD $(SERVER)"
|
||||||
|
$(CC) $(LDFLAGS) $(SOBJS) $(COMMOBJS) -o $(SERVER)
|
||||||
|
@rm $(COMMOBJS)
|
||||||
|
|
||||||
|
|
||||||
|
$(OBJDIR):
|
||||||
|
mkdir $(OBJDIR)
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: %.c
|
||||||
|
@echo -e "\t\tCC $<"
|
||||||
|
$(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo -e "\t\tCLEAN"
|
||||||
|
@rm -f $(OBJS) $(DEPS)
|
||||||
|
@rmdir $(OBJDIR) 2>/dev/null || true
|
||||||
|
|
||||||
|
xclean: clean
|
||||||
|
@rm -f $(PROGRAM)
|
||||||
|
|
||||||
|
.PHONY: clean xclean
|
||||||
7
Socket_CAN/README_ports
Normal file
7
Socket_CAN/README_ports
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
server:
|
||||||
|
socat pty,link=/tmp/ttyX0,waitslave tcp:127.0.0.1:2002 &
|
||||||
|
ssh -L 2002:robotel1:2000 -N -f robotel1 &
|
||||||
|
|
||||||
|
client:
|
||||||
|
|
||||||
|
socat TCP-LISTEN:2000 PTY,link=/tmp/ttyX0,raw,crnl &
|
||||||
15
Socket_CAN/Readme.md
Normal file
15
Socket_CAN/Readme.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
CANbus messages retranslation from BTA bus into Dome bus
|
||||||
|
|
||||||
|
RUN server:
|
||||||
|
|
||||||
|
./soccanserver -i localhost -l log.log -a ca/ca/ca_cert.pem -c ca/server/server_cert.pem -k ca/server/private/server_key.pem
|
||||||
|
|
||||||
|
|
||||||
|
RUN client:
|
||||||
|
|
||||||
|
./soccanclient -i localhost -a ca/ca/ca_cert.pem -c ca/client/client_cert.pem -k ca/client/private/client_key.pem
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Compile i686:
|
||||||
|
export LDFLAGS=-m32
|
||||||
1
Socket_CAN/SocketCAN.cflags
Normal file
1
Socket_CAN/SocketCAN.cflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c17
|
||||||
6
Socket_CAN/SocketCAN.config
Normal file
6
Socket_CAN/SocketCAN.config
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Add predefined macros for your project here. For example:
|
||||||
|
// #define THE_ANSWER 42
|
||||||
|
#define EBUG
|
||||||
|
#define SERVER
|
||||||
|
#define CLIENT
|
||||||
|
#define _GNU_SOURCE
|
||||||
1
Socket_CAN/SocketCAN.creator
Normal file
1
Socket_CAN/SocketCAN.creator
Normal file
@ -0,0 +1 @@
|
|||||||
|
[General]
|
||||||
159
Socket_CAN/SocketCAN.creator.user
Normal file
159
Socket_CAN/SocketCAN.creator.user
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE QtCreatorProject>
|
||||||
|
<!-- Written by QtCreator 4.15.1, 2021-12-15T14:17:48. -->
|
||||||
|
<qtcreator>
|
||||||
|
<data>
|
||||||
|
<variable>EnvironmentId</variable>
|
||||||
|
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||||
|
<value type="int">0</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||||
|
<value type="QString" key="language">Cpp</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||||
|
<value type="QString" key="language">QmlJS</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||||
|
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||||
|
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<valuemap type="QVariantMap" key="ClangTools">
|
||||||
|
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||||
|
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||||
|
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||||
|
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||||
|
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="QString" key="DeviceType">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||||
|
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/ELECTRONICS/CAN_controller/Socket_CAN</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">all</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">clean</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Default</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||||
|
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||||
|
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||||
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||||
|
<value type="int">1</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||||
|
<value type="int">22</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>Version</variable>
|
||||||
|
<value type="int">22</value>
|
||||||
|
</data>
|
||||||
|
</qtcreator>
|
||||||
1
Socket_CAN/SocketCAN.cxxflags
Normal file
1
Socket_CAN/SocketCAN.cxxflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c++17
|
||||||
16
Socket_CAN/SocketCAN.files
Normal file
16
Socket_CAN/SocketCAN.files
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Makefile
|
||||||
|
can4linux.h
|
||||||
|
can_io.c
|
||||||
|
can_io.h
|
||||||
|
canbus.h
|
||||||
|
cansock.c
|
||||||
|
client.c
|
||||||
|
client.h
|
||||||
|
cmdlnopts.c
|
||||||
|
cmdlnopts.h
|
||||||
|
daemon.c
|
||||||
|
daemon.h
|
||||||
|
server.c
|
||||||
|
server.h
|
||||||
|
sslsock.c
|
||||||
|
sslsock.h
|
||||||
1
Socket_CAN/SocketCAN.includes
Normal file
1
Socket_CAN/SocketCAN.includes
Normal file
@ -0,0 +1 @@
|
|||||||
|
.
|
||||||
32
Socket_CAN/ca/ca/ca_cert.pem
Normal file
32
Socket_CAN/ca/ca/ca_cert.pem
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
jfORPJGT7YvQ0nFHf9V3Bw2ynuaSUzU=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
1
Socket_CAN/ca/ca/ca_cert.srl
Normal file
1
Socket_CAN/ca/ca/ca_cert.srl
Normal file
@ -0,0 +1 @@
|
|||||||
|
1D339878EE448B717AB9855CC9DFBBC66C06FF8D
|
||||||
52
Socket_CAN/ca/ca/private/ca_key.pem
Normal file
52
Socket_CAN/ca/ca/private/ca_key.pem
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
XiPSjQhMjqLaniianqcVkhCKCicsk0c=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
27
Socket_CAN/ca/client/client.csr
Normal file
27
Socket_CAN/ca/client/client.csr
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIEhDCCAmwCAQAwPzELMAkGA1UEBhMCUlUxDTALBgNVBAgMBEtDaFIxDzANBgNV
|
||||||
|
BAcMBkJ1a292bzEQMA4GA1UECgwHU0FPIFJBUzCCAiIwDQYJKoZIhvcNAQEBBQAD
|
||||||
|
ggIPADCCAgoCggIBALwxkEemASoXwJu8qEIFhnOqrn50Gj6xI8O4/2RyyB35nisR
|
||||||
|
3VB24a5cdBvXzCq7PfuVzCtHCnKbLxPJhA5HJAB4MHOyXH97NKp0Ihpp/8A3FWJq
|
||||||
|
/oNF0QpnBlSKVlQ/5Omh7kWzzqNlQHIIJpgyZZJlePi1RBjCK0h+HZMg+/1jutvt
|
||||||
|
FRGXOcbRLke8Vm5NSmdPBAYLCzaoByCCqefhxmdiSnUC6TgPqiGgSxQ7SSMB/sdb
|
||||||
|
ADd9e8pEZRGWMyU2z6X8GtuyRkIKC4txdPYdAxBNSe32nHDOx4RE0GsjSzqCQ2di
|
||||||
|
+mzh4mbeQGJLQprqNRLbR1moppumBM9qatL9bDr+NIOJVj9y2RqmEbuXLzV8f0vM
|
||||||
|
v61k89ZlQJro5y+4AffwpKXDrHqXaALhUvD80xZDvTRRZrBTC5cLvCC/Qx5Lq8hI
|
||||||
|
/Yp/N8E4ZLIJGL0PJ0gKiuUQabLGNydqLxLuDp4nwPvRQdsB/MVErlw1ojA9L0wN
|
||||||
|
WvxTJl5tCflcIH9imCceuIhGP9+TGuJdknZPk1pl97wfQjWGunbkHWzw20bQXL1f
|
||||||
|
sqZOYHIaRjX/TRsIo8A6xOo9tM+J8tlkr6Vbf177xv+yxblMOhMnbi77efSKDImj
|
||||||
|
mqrAm7EzxzOximrAxRjJEANtgfoFCY205cwM8uepnJYoTg4ZY4YLuHX9lInvAgMB
|
||||||
|
AAGgADANBgkqhkiG9w0BAQsFAAOCAgEAsiA2FfbdcQCFlYhgD2vZZMqOvJD3IfT+
|
||||||
|
2Jt1QTfLBiPtqCIa20A6lHCaRQ8FxQ3IbpJpSlpJ9Abj1UqOkNFHKCHIfIbkITr9
|
||||||
|
uG/UlWu3dQ0FnmxpM5i6Vm4yEgZymGbNDObmCP50Ai1mtGpFjb3lYIv8sgX/e9+B
|
||||||
|
d/evTvzH+QjSWGzABLe7uMv94wkjWm+LFSVT9XIQ8FzkoIz17QQTcg8q5ku5qveW
|
||||||
|
SYmOS3rOxWzh+kYJG8+qkLw9ga6T+/lydzqb6gr7iW2pEUSFCWpwb9v7yFk8uZ6L
|
||||||
|
NZe3YW6e601uqzPpvH0/aQSIbnh//vVTHxFitA+lCENYgIaz8/TAT3/VQhCiM3OZ
|
||||||
|
cTEZWIPRtlV84c9kIvxfYTthmS3vnFPSMvI5STUmFA1MSvuxOx1c5BUtdlMv/58x
|
||||||
|
WL8btQB1oRqt6KuMKnwsUA8nv84MRzkH0tCatmcuAIy2/NXrsbo/F794jwCFJFWp
|
||||||
|
nEoKFnCIhpFvAYTV70BV0jkAQ3iLV4RpU6LdqdVtzDQbjbFd/bWIjT/A7/xEoMI7
|
||||||
|
jaJfPE/1JaDnzFD20WTSXU1SrOcFlDRURrfYRrWMxaqCHBQbp+OwTaa3ut928tZk
|
||||||
|
Gs/m+Ov6hMNt54tbBmc2Yc42rbBStBbUKjO4YpwMbFm/dyjFZ4dGx/K54XMve7R6
|
||||||
|
dFl5goynSwo=
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
||||||
30
Socket_CAN/ca/client/client_cert.pem
Normal file
30
Socket_CAN/ca/client/client_cert.pem
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
myCZgwzp8pk0xfV1
|
||||||
|
-----END CERTIFICATE-----
|
||||||
51
Socket_CAN/ca/client/private/client_key.pem
Normal file
51
Socket_CAN/ca/client/private/client_key.pem
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIJKAIBAAKCAgEAvDGQR6YBKhfAm7yoQgWGc6qufnQaPrEjw7j/ZHLIHfmeKxHd
|
||||||
|
UHbhrlx0G9fMKrs9+5XMK0cKcpsvE8mEDkckAHgwc7Jcf3s0qnQiGmn/wDcVYmr+
|
||||||
|
g0XRCmcGVIpWVD/k6aHuRbPOo2VAcggmmDJlkmV4+LVEGMIrSH4dkyD7/WO62+0V
|
||||||
|
EZc5xtEuR7xWbk1KZ08EBgsLNqgHIIKp5+HGZ2JKdQLpOA+qIaBLFDtJIwH+x1sA
|
||||||
|
N317ykRlEZYzJTbPpfwa27JGQgoLi3F09h0DEE1J7faccM7HhETQayNLOoJDZ2L6
|
||||||
|
bOHiZt5AYktCmuo1EttHWaimm6YEz2pq0v1sOv40g4lWP3LZGqYRu5cvNXx/S8y/
|
||||||
|
rWTz1mVAmujnL7gB9/CkpcOsepdoAuFS8PzTFkO9NFFmsFMLlwu8IL9DHkuryEj9
|
||||||
|
in83wThksgkYvQ8nSAqK5RBpssY3J2ovEu4OnifA+9FB2wH8xUSuXDWiMD0vTA1a
|
||||||
|
/FMmXm0J+Vwgf2KYJx64iEY/35Ma4l2Sdk+TWmX3vB9CNYa6duQdbPDbRtBcvV+y
|
||||||
|
pk5gchpGNf9NGwijwDrE6j20z4ny2WSvpVt/XvvG/7LFuUw6EyduLvt59IoMiaOa
|
||||||
|
qsCbsTPHM7GKasDFGMkQA22B+gUJjbTlzAzy56mclihODhljhgu4df2Uie8CAwEA
|
||||||
|
AQKCAgBsnqbJ09SkOOVgffkXchzyMbdZISXsvU0JMIOntGAwfNx/u2XjhVooyw/w
|
||||||
|
6hLbLwtNZF5dNDmhgFQhtZPUsdbjtnswq+ebZL83CqSMXlXQ2XosPdj8Z5WJzYDn
|
||||||
|
1piRM/epqV7fODKyOESEDJRKD/x0DMFPuz+8koVs5+2l98m5rJAzU5lvd7tPN3jg
|
||||||
|
yqGQNGgXTJHj8wfb2guTBheO0M806JRVCQMW6mOl2OC8oqNJ42LsKWfsny6NxgAX
|
||||||
|
sHuApSwgf2v5FeJbR3T2XNvHGWOlSxa6lDYjHhYmD5nD3LEU6g6BY61qns2P1gOP
|
||||||
|
OCUPSNKtOYbrBt5yw9XO6XsSoFaQkKsbnSV4aU/VQFsOp4/yk2xgGfBLN0LkZEGn
|
||||||
|
EcNJauuJ2qxuukn4zjB9KeK8tkgzGrKmlQ3y7az5wA3FaYPxpSg6UZmzDHN9mpJW
|
||||||
|
T1vbj29kDb4QmxHOE1qHyKrqwzUMpDR1zY0WYgPK80MPFlvOm9K1lR5zTH8R4Fmq
|
||||||
|
oIPAeSIwBOEbGl4K0S/g1j/R/pnHYXU0DXIgmkbST+Qz8BXKphQ2r3dYJp+/8et8
|
||||||
|
J1iE3LWBjtPLflRhiW0mqyH9QM9cbYyOKC/Qs62Azt8pIy+eNxpXd5AdUS/l2Gig
|
||||||
|
3Wp60gABLLM703fFsHkrWuKUh6dLx+6yMxN3vKx2kFO+UZe58QKCAQEA4J1b6boF
|
||||||
|
hwKqMBDni9/JM2PPx4wYrqJ3Q8XOaBJdQjQ4ltFcOC1dDv9RMQGs9sdVrjCL1fNT
|
||||||
|
uxUu+A6D0g1V9EeGG1nYQRyVrvoqe1sYV1PrPhxtEvoZ0GLsA/KRLjtQp6dfyOoj
|
||||||
|
rHackV9+8AzQHZS4K6H17r0+SuRMfNznH5WWvQBRbql+nLMem26PIRJ2ZZvOiiP7
|
||||||
|
gpT/wcsfY9e+jZyz3nRq7N2HC2r7IWHTImrq2kzqreEqE9n/lSvleIhhc6vlT7j9
|
||||||
|
Yw4xbm+HxTL5LEYIIOrg3LL50+CJFixRs6jj5ZcCnIoG6QOh5xkK4ceI5exGii1J
|
||||||
|
WpmbVOHfSrc4awKCAQEA1n1k/hF9G2MEUsEYdnfP/lfspgCjba9MRJBWsVqyA4d3
|
||||||
|
DjMcPHUCpmG2zXzK2HAmg+MWlVPFAp/LtLcXcVYHvCbnpyYikvUibUaggIB0vSpw
|
||||||
|
3UFrb0uOzPlrmvP5Gx/t3Mjo6kKntNrDjgfhhqS0cInFOGsf2K3zrDNTfrKzzQPh
|
||||||
|
96xwNbhfUP6scvc4XZ9mb6wkykIDvEafrp17LXemVn4q2+CwiEPBxshmvm45NG23
|
||||||
|
LS++JKOAOdvU11H9ZphQRN4ZjmQgtt8aqiV1uSl6a7Mo2kBwNStAKfjEvnTZhmy8
|
||||||
|
YDN3iGgVtHgwuiV/kr7YVVs2HjfeUCyHgYhgD0kljQKCAQBpa5Gi/irv9eE4lAaI
|
||||||
|
0KyXEQaJKoi/FgOR7Hn2wH/Cvc29g1+cAjaF/nD15kpuvJnLGn/XF9A5ozSbOfzG
|
||||||
|
jnnEH/miRqXH0YmzSTi9EsE2420qhp7u5DFPa85IAAYBw9cUCOtc2f+KR1Uuqbpj
|
||||||
|
IjBfYdiaqfZKacmdzs7TX76eRVAtPsP5g1WoaC06WEaXCBpHkDv8++xkmlf7dcEy
|
||||||
|
1CRcRKrrAorYxxRF2J0rSsWUhsfZU3Zly6M7E/rv4V1fF+tdJdWHeFR8tEGhCnmX
|
||||||
|
pVfrXqccBAErtFirB9xvareh8eecbybLn8Ckho7rbwZ7d3IaL63f1mdyPVv5F9X8
|
||||||
|
NEgnAoIBACM7U7R8EO3HtPUW7LrA8XRY4vFdl3qz2bZFc0gMmsMDpGW7tX6kxbuo
|
||||||
|
v0s/nV4yBdGSIqqCqRDGSMK1dG9Ub07ToSeOlw1GoNIMUN7qusI7z3A4h7ovUhSP
|
||||||
|
P8KjIp72/q5OfhvEuSF28bpJxxzDvzPhHXkn94IzCJyXjbZ5Chm58ospUwEv+NAo
|
||||||
|
FRGJVEPkpAHh5+UlNNHfU+ltysbsKXF5pfaaEMVBQ/ov/th26ISZJQaSGgyQosZe
|
||||||
|
Orbnq9UHXeACD3aZMdp4CTw7jPvOOWKpeiNnhEbnhNGgIEkcjoKLJ+IxcggA+Ne9
|
||||||
|
Clv5PtxO5uAWbGxIRwcqWVPIn+bC4B0CggEBAKUSSNaV4x063NxQVtgmkvzSVzhD
|
||||||
|
oO2zB31TVizIKWgf+7/oJiU7GHs/CItFhweK42Z3x8++xUjsJpykAZUbPEqPG8om
|
||||||
|
43Poab+H6/6groR+AziwPYwR0h5uafj6GuPXHEzoIMveJKPlpGzV6RgjwCGbG01n
|
||||||
|
Vas6+O/SQVXE2E1sm3FU/ykWAoYmAp7GuvsW43En/yCHdr9sv4zurvebZSKVU8IS
|
||||||
|
0R0U5Z3SjYdI8IawgaL1L/jhvIdF5ak1vxvsm3X0hkw8Zs7KoZjlcD8fW1+RAP7i
|
||||||
|
KKHlFji3C/Q6/zeKYHjj4obvLd5Udr3EeaEsD67OQArdYM37htKI+ne033c=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
49
Socket_CAN/ca/gen.sh
Executable file
49
Socket_CAN/ca/gen.sh
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# https://gist.github.com/zapstar/4b51d7cfa74c7e709fcdaace19233443
|
||||||
|
mkdir -p ca/private
|
||||||
|
chmod 700 ca/private
|
||||||
|
# NOTE: I'm using -nodes, this means that once anybody gets
|
||||||
|
# their hands on this particular key, they can become this CA.
|
||||||
|
openssl req \
|
||||||
|
-x509 \
|
||||||
|
-nodes \
|
||||||
|
-days 36524 \
|
||||||
|
-newkey rsa:4096 \
|
||||||
|
-keyout ca/private/ca_key.pem \
|
||||||
|
-out ca/ca_cert.pem \
|
||||||
|
-subj "/C=RU/ST=KChR/L=Bukovo/O=SAO RAS/CN=sao.ru"
|
||||||
|
|
||||||
|
# Create server private key and certificate request
|
||||||
|
mkdir -p server/private
|
||||||
|
chmod 700 ca/private
|
||||||
|
openssl genrsa -out server/private/server_key.pem 4096
|
||||||
|
openssl req -new \
|
||||||
|
-key server/private/server_key.pem \
|
||||||
|
-out server/server.csr \
|
||||||
|
-subj "/C=RU/ST=KChR/L=Bukovo/O=SAO RAS"
|
||||||
|
|
||||||
|
# Create client private key and certificate request
|
||||||
|
mkdir -p client/private
|
||||||
|
chmod 700 client/private
|
||||||
|
openssl genrsa -out client/private/client_key.pem 4096
|
||||||
|
openssl req -new \
|
||||||
|
-key client/private/client_key.pem \
|
||||||
|
-out client/client.csr \
|
||||||
|
-subj "/C=RU/ST=KChR/L=Bukovo/O=SAO RAS"
|
||||||
|
|
||||||
|
# Generate certificates
|
||||||
|
openssl x509 -req -days 36524 -in server/server.csr \
|
||||||
|
-CA ca/ca_cert.pem -CAkey ca/private/ca_key.pem \
|
||||||
|
-CAcreateserial -out server/server_cert.pem
|
||||||
|
openssl x509 -req -days 36524 -in client/client.csr \
|
||||||
|
-CA ca/ca_cert.pem -CAkey ca/private/ca_key.pem \
|
||||||
|
-CAcreateserial -out client/client_cert.pem
|
||||||
|
|
||||||
|
# Now test both the server and the client
|
||||||
|
# On one shell, run the following
|
||||||
|
# openssl s_server -CAfile ca/ca_cert.pem -cert server/server_cert.pem -key server/private/server_key.pem -Verify 1
|
||||||
|
# On another shell, run the following
|
||||||
|
# openssl s_client -CAfile ca/ca_cert.pem -cert client/client_cert.pem -key client/private/client_key.pem
|
||||||
|
# Once the negotiation is complete, any line you type is sent over to the other side.
|
||||||
|
# By line, I mean some text followed by a keyboard return press.
|
||||||
51
Socket_CAN/ca/server/private/server_key.pem
Normal file
51
Socket_CAN/ca/server/private/server_key.pem
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
27
Socket_CAN/ca/server/server.csr
Normal file
27
Socket_CAN/ca/server/server.csr
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIEhDCCAmwCAQAwPzELMAkGA1UEBhMCUlUxDTALBgNVBAgMBEtDaFIxDzANBgNV
|
||||||
|
BAcMBkJ1a292bzEQMA4GA1UECgwHU0FPIFJBUzCCAiIwDQYJKoZIhvcNAQEBBQAD
|
||||||
|
ggIPADCCAgoCggIBAM/Iqcldh+6UfwTJySrY7WpzFlUTq2c0nwTyvRDDP1+R9Ryt
|
||||||
|
zyOwnkKMRvU4Bs40iftpacwlU4JfQGGeQn1g7507rRlalIxt11D2kB+hHh7V8pS1
|
||||||
|
3Y5Y1yOTZlhExdKrs1A3EpaEl4wurF2Rxk6fQMfGoi18Tx/jvjy5diT2LTWv+KOb
|
||||||
|
xFIJv7o0ikLdvdLFdqobWn4xaYNjP6M7+3IlWCU8N0ickAprKBHOf9jFgE3ABjNu
|
||||||
|
MYUY1gX9dJbkEbhjrvIcbjC5MmknMoR1HHbG8MHLgEbcbu0ZFgj7pu01QfiByEbL
|
||||||
|
gDT1xl4pZ8S+6d4q7lPmkwmJzwGJr5ZmCqyT7A4i01AqVRHbezZvR0oV4QusErhK
|
||||||
|
xvGh7123H/OrSvfwIxEIbWEAIzvWaxV14ctLKOiOw+mENltQxFWziaiGNHXM38SH
|
||||||
|
QNSmTHJUWC08IUqslR5r1Ys4h15vdJ+ZMVpw1ijNIW0C9zgdJu/ERkaCnVSW5rl3
|
||||||
|
gicou4NobomKscHfnyYTiPUWZ+GccnNR35xlSbGSmjzPwYtvvX0UOn8wSp2oCeW6
|
||||||
|
PQuWJDpVOlTFgQwJNVT6T9J2XW/wtlNWyZGjM3tATqAlpXTrrapJzTlLuEGpkebK
|
||||||
|
IMTLnDa/DXemy1A7ehjyKMXfXC4pzwEsR12oPfZ1qyO+lQJPYV0Ur+onSNlZAgMB
|
||||||
|
AAGgADANBgkqhkiG9w0BAQsFAAOCAgEAAD2CuiczzQnU0+W2lYGuxueCbIkD6ZW0
|
||||||
|
li48K4iu5kp2Axv4H/d9o61nHn8E+fqkZLNB10eIut/45yRXUA6cWjBTtMZR1Gcz
|
||||||
|
BFXnaau1agCnFEqqanU7uBJpflQD+soieICjtQGyrqCTSJlaZy9V/iv5lYCvCn8T
|
||||||
|
mP9yiUkoAKOnAf/XHLkyBrt7IW2ovT5raMcBj0z/5GNNKouhu2kdWEk/BH9zMvYY
|
||||||
|
uccf2+YMbtdHDUG+0qlSVAYOyDONbJgHAFfROVdlfN2mVDMkUSnSg9/IE4aevP9s
|
||||||
|
LuHBzCJzodRqpMuIgV+GtTETzWcZvnaXKLmOvKCnLQtxP2OZYrF4EwxK2SdDPCW+
|
||||||
|
YQYu51YF/tBumZbCWrGThg5YYGJfghTaINr8x51j1lQNBTGh1gi3I5633eGtIlpW
|
||||||
|
HUaY49KSQ+yBefmHMWesC6dbSbHfqvfbugidVAk8eFNS3weo26AJsv3dPNKani/+
|
||||||
|
c0bOeEJ4tfIQUEpTRlPC5MWqEk0/wz9XC1hPAYHV4YZExQ+kBQ2xyEa0w/9yLuWG
|
||||||
|
5sZjd/k/XBnz/V6rrx+jPeqikaaScCGR8YpCwglWEmn6K1Mp6ciSNAFqGTeVnhwD
|
||||||
|
U0E3INACyi984vDzL886zWt7J1zT0t6IpIaDnxDpmoqvJDK5+xVaw4059HeXwaYb
|
||||||
|
5zpySGMozeg=
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
||||||
30
Socket_CAN/ca/server/server_cert.pem
Normal file
30
Socket_CAN/ca/server/server_cert.pem
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
Qx01GFwRqiRjVnId
|
||||||
|
-----END CERTIFICATE-----
|
||||||
211
Socket_CAN/can4linux.h
Normal file
211
Socket_CAN/can4linux.h
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* can4linux.h - can4linux CAN driver module
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
* License. See the file "COPYING" in the main directory of this archive
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2001 port GmbH Halle/Saale
|
||||||
|
*------------------------------------------------------------------
|
||||||
|
* $Header: /z2/cvsroot/products/0530/software/can4linux/src/can4linux.h,v 1.5 2004/05/14 10:02:54 oe Exp $
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* modification history
|
||||||
|
* --------------------
|
||||||
|
* $Log: can4linux.h,v $
|
||||||
|
* Revision 1.5 2004/05/14 10:02:54 oe
|
||||||
|
* - started supporting CPC-Card
|
||||||
|
* - version number in can4linux.h available
|
||||||
|
* - only one structure type for Config_par_t Command_par_t
|
||||||
|
* - new ioctl command CMD_CLEARBUFFERS
|
||||||
|
*
|
||||||
|
* Revision 1.4 2003/08/27 17:49:04 oe
|
||||||
|
* - New CanStatusPar structure
|
||||||
|
*
|
||||||
|
* Revision 1.3 2002/08/20 05:57:22 oe
|
||||||
|
* - new write() handling, now not ovrwriting buffer content if buffer fill
|
||||||
|
* - ioctl() get status returns buffer information
|
||||||
|
*
|
||||||
|
* Revision 1.2 2002/08/08 17:50:46 oe
|
||||||
|
* - MSG_ERR_MASK extended
|
||||||
|
*
|
||||||
|
* Revision 1.1 2002/01/10 19:13:19 oe
|
||||||
|
* - application header file changed name can.h -> can4linux.h
|
||||||
|
*
|
||||||
|
* Revision 1.2 2001/09/14 14:58:09 oe
|
||||||
|
* first free release
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2001/06/11 18:30:54 oe
|
||||||
|
* minimal version can4linux embedded, compile time Konfigurierbar
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file can.h
|
||||||
|
* \author Heinz-Jürgen Oertel, port GmbH
|
||||||
|
* $Revision: 1.5 $
|
||||||
|
* $Date: 2004/05/14 10:02:54 $
|
||||||
|
*
|
||||||
|
* can4linux interface definitions
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __CAN_H
|
||||||
|
#define __CAN_H
|
||||||
|
|
||||||
|
|
||||||
|
#define CAN4LINUXVERSION 0x0301 /*(Version 3.1)*/
|
||||||
|
|
||||||
|
#ifndef __KERNEL__
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
/*---------- the can message structure */
|
||||||
|
|
||||||
|
#define CAN_MSG_LENGTH 8 /**< maximum length of a CAN frame */
|
||||||
|
|
||||||
|
|
||||||
|
#define MSG_RTR (1<<0) /**< RTR Message */
|
||||||
|
#define MSG_OVR (1<<1) /**< CAN controller Msg overflow error */
|
||||||
|
#define MSG_EXT (1<<2) /**< extended message format */
|
||||||
|
#define MSG_PASSIVE (1<<4) /**< controller in error passive */
|
||||||
|
#define MSG_BUSOFF (1<<5) /**< controller Bus Off */
|
||||||
|
#define MSG_ (1<<6) /**< */
|
||||||
|
#define MSG_BOVR (1<<7) /**< receive/transmit buffer overflow */
|
||||||
|
/**
|
||||||
|
* mask used for detecting CAN errors in the canmsg_t flags field
|
||||||
|
*/
|
||||||
|
#define MSG_ERR_MASK (MSG_OVR + MSG_PASSIVE + MSG_BUSOFF + MSG_BOVR)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CAN message structure.
|
||||||
|
* Used for all data transfers between the application and the driver
|
||||||
|
* using read() or write().
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** flags, indicating or controlling special message properties */
|
||||||
|
int flags;
|
||||||
|
int cob; /**< CAN object number, used in Full CAN */
|
||||||
|
unsigned long id; /**< CAN message ID, 4 bytes */
|
||||||
|
struct timeval timestamp; /**< time stamp for received messages */
|
||||||
|
short int length; /**< number of bytes in the CAN message */
|
||||||
|
unsigned char data[CAN_MSG_LENGTH]; /**< data, 0...8 bytes */
|
||||||
|
} canmsg_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
---------- IOCTL requests */
|
||||||
|
|
||||||
|
#define COMMAND 0 /**< IOCTL command request */
|
||||||
|
#define CONFIG 1 /**< IOCTL configuration request */
|
||||||
|
#define SEND 2 /**< IOCTL request */
|
||||||
|
#define RECEIVE 3 /**< IOCTL request */
|
||||||
|
#define CONFIGURERTR 4 /**< IOCTL request */
|
||||||
|
#define STATUS 5 /**< IOCTL status request */
|
||||||
|
|
||||||
|
/*---------- CAN ioctl parameter types */
|
||||||
|
/**
|
||||||
|
IOCTL Command request parameter structure */
|
||||||
|
struct Command_par {
|
||||||
|
int cmd; /**< special driver command */
|
||||||
|
int target; /**< special configuration target */
|
||||||
|
unsigned long val1; /**< 1. parameter for the target */
|
||||||
|
unsigned long val2; /**< 2. parameter for the target */
|
||||||
|
int error; /**< return value */
|
||||||
|
unsigned long retval; /**< return value */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct Command_par Command_par_t ;
|
||||||
|
/**
|
||||||
|
PSW made them all the same
|
||||||
|
IOCTL Configuration request parameter structure */
|
||||||
|
typedef struct Command_par Config_par_t ;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
IOCTL generic CAN controller status request parameter structure */
|
||||||
|
typedef struct CanStatusPar {
|
||||||
|
unsigned int baud; /**< actual bit rate */
|
||||||
|
unsigned int status; /**< CAN controller status register */
|
||||||
|
unsigned int error_warning_limit; /**< the error warning limit */
|
||||||
|
unsigned int rx_errors; /**< content of RX error counter */
|
||||||
|
unsigned int tx_errors; /**< content of TX error counter */
|
||||||
|
unsigned int error_code; /**< content of error code register */
|
||||||
|
unsigned int rx_buffer_size; /**< size of rx buffer */
|
||||||
|
unsigned int rx_buffer_used; /**< number of messages */
|
||||||
|
unsigned int tx_buffer_size; /**< size of tx buffer */
|
||||||
|
unsigned int tx_buffer_used; /**< number of messages */
|
||||||
|
unsigned long retval; /**< return value */
|
||||||
|
unsigned int type; /**< CAN controller / driver type */
|
||||||
|
} CanStatusPar_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
IOCTL CanStatusPar.type CAN controller hardware chips */
|
||||||
|
#define CAN_TYPE_UNSPEC 0
|
||||||
|
#define CAN_TYPE_SJA1000 1
|
||||||
|
#define CAN_TYPE_FlexCAN 2
|
||||||
|
#define CAN_TYPE_TouCAN 3
|
||||||
|
#define CAN_TYPE_82527 4
|
||||||
|
#define CAN_TYPE_TwinCAN 5
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
IOCTL Send request parameter structure */
|
||||||
|
typedef struct Send_par {
|
||||||
|
canmsg_t *Tx; /**< CAN message struct */
|
||||||
|
int error; /**< return value for errno */
|
||||||
|
unsigned long retval; /**< return value */
|
||||||
|
} Send_par_t ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
IOCTL Receive request parameter structure */
|
||||||
|
typedef struct Receive_par {
|
||||||
|
canmsg_t *Rx; /**< CAN message struct */
|
||||||
|
int error; /**< return value for errno */
|
||||||
|
unsigned long retval; /**< return value */
|
||||||
|
} Receive_par_t ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
IOCTL ConfigureRTR request parameter structure */
|
||||||
|
typedef struct ConfigureRTR_par {
|
||||||
|
unsigned message; /**< CAN message ID */
|
||||||
|
canmsg_t *Tx; /**< CAN message struct */
|
||||||
|
int error; /**< return value for errno */
|
||||||
|
unsigned long retval; /**< return value */
|
||||||
|
} ConfigureRTR_par_t ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
---------- IOCTL Command subcommands and there targets */
|
||||||
|
|
||||||
|
# define CMD_START 1
|
||||||
|
# define CMD_STOP 2
|
||||||
|
# define CMD_RESET 3
|
||||||
|
# define CMD_CLEARBUFFERS 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
---------- IOCTL Configure targets */
|
||||||
|
|
||||||
|
# define CONF_ACC 0 /* mask and code */
|
||||||
|
# define CONF_ACCM 1 /* mask only */
|
||||||
|
# define CONF_ACCC 2 /* code only */
|
||||||
|
# define CONF_TIMING 3 /* bit timing */
|
||||||
|
# define CONF_OMODE 4 /* output control register */
|
||||||
|
# define CONF_FILTER 5
|
||||||
|
# define CONF_FENABLE 6
|
||||||
|
# define CONF_FDISABLE 7
|
||||||
|
|
||||||
|
#endif /* __CAN_H */
|
||||||
545
Socket_CAN/can_io.c
Normal file
545
Socket_CAN/can_io.c
Normal file
@ -0,0 +1,545 @@
|
|||||||
|
/* CAN I/O library (to use as a process)
|
||||||
|
* usage:
|
||||||
|
* first: fork() + start_can_io(NULL) - start CAN Rx-buffering process
|
||||||
|
* then: fork() + Control_1(....) - start process that uses recv/send functions
|
||||||
|
* ...........................
|
||||||
|
* then: fork() + Control_N(....)
|
||||||
|
*
|
||||||
|
* note: use init_can_io() at the begining of every Control process
|
||||||
|
* BUT DON't USE it in main() before Control process start
|
||||||
|
* ^^^^^^^^^^^^^
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/msg.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
|
||||||
|
#include "can4linux.h"
|
||||||
|
#include "can_io.h"
|
||||||
|
|
||||||
|
char can_dev[40] = "/dev/can0";
|
||||||
|
int can_fd=-1;
|
||||||
|
char can_lck[40] = "/tmp/dev_can0.lock";
|
||||||
|
int can_lk=-1;
|
||||||
|
static int server_mode=0;
|
||||||
|
static int my_uid;
|
||||||
|
|
||||||
|
#define CAN_SHM_SIZE ((sizeof(int)*3)+CAN_CTLR_SIZE+(CAN_RX_SIZE*sizeof(canmsg_t)))
|
||||||
|
|
||||||
|
union ShMkey {
|
||||||
|
char name[5];
|
||||||
|
key_t code;
|
||||||
|
} can_shm_key;
|
||||||
|
int can_shm_id=-1;
|
||||||
|
char *can_shm_addr = NULL;
|
||||||
|
#define can_pid (*(((int *)can_shm_addr)+0)) /* PID of CAN I/O process */
|
||||||
|
#define can_open (*(((int *)can_shm_addr)+1)) /* file descr.of CAN-driver */
|
||||||
|
#define rx_buff_pntr (*(((int *)can_shm_addr)+2)) /* from 0 till CAN_RX_SIZE-1 */
|
||||||
|
void *can_ctrl_addr = NULL; /* shm area reserved for control process purpose*/
|
||||||
|
canmsg_t *rx_buff; /* rx ring buffer: CAN_RX_SIZE*sizeof(canmsg_t)*/
|
||||||
|
|
||||||
|
struct CMD_Queue { /* ÏÐÉÓÁÎÉÅ ÏÞÅÒÅÄÉ (ËÁÎÁÌÁ) ËÏÍÁÎÄ */
|
||||||
|
union {
|
||||||
|
char name[5]; /* ËÌÀÞ ÉÄÅÎÔÅÆÉËÁÃÉÉ ÏÞÅÒÅÄÉ */
|
||||||
|
key_t code;
|
||||||
|
} key;
|
||||||
|
int mode; /* ÒÅÖÉÍ ÄÏÓÔÕÐÁ (rwxrwxrwx) */
|
||||||
|
int side; /* ÔÉÐ ÐÏÄÓÏÅÄÉÎÅÎÉÑ: ëÌÉÅÎÔ/óÅÒ×ÅÒ (Sender/Receiver)*/
|
||||||
|
int id; /* ÄÅÓËÒÉÐÔÏÒ ÐÏÄÓÏÅÄÉÎÅÎÉÑ */
|
||||||
|
unsigned int acckey; /* ËÌÀÞ ÄÏÓÔÕÐÁ (ÄÌÑ ÐÅÒÅÄÁÞÉ ëÌÉÅÎÔ->óÅÒ×ÅÒ) */
|
||||||
|
};
|
||||||
|
/* ËÁÎÁÌ ËÏÍÁÎÄ ÉÓÐÏÌØÚÕÅÍ ÄÌÑ ÐÅÒÅÄÁÞÉ CAN-ÆÒÅÊÍÏ× */
|
||||||
|
static struct CMD_Queue canout = {{{'C','A','N',0,0}},0200,0,-1,0};
|
||||||
|
|
||||||
|
/* ÓÔÒÕËÔÕÒÁ ÓÏÏÂÝÅÎÉÑ */
|
||||||
|
struct my_msgbuf {
|
||||||
|
long mtype; /* type of message */
|
||||||
|
unsigned long acckey; /* ËÌÀÞ ÄÏÓÔÕÐÁ ËÌÉÅÎÔÁ */
|
||||||
|
unsigned long src_pid; /* ÎÏÍÅÒ ÐÒÏÃÅÓÓÁ ÉÓÔÏÞÎÉËÁ */
|
||||||
|
unsigned long src_ip; /* IP-ÁÄÒ. ÉÓÔÏÞÎÉËÁ, =0 - ÌÏËÁÌØÎÁÑ ËÏÍÁÎÄÁ */
|
||||||
|
char mtext[100]; /* message text */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void can_abort(int sig);
|
||||||
|
|
||||||
|
void set_server_mode(int mode) {server_mode=mode;}
|
||||||
|
int can_server() {return(server_mode);}
|
||||||
|
int can_card() {return(can_fd>0);}
|
||||||
|
int can_gate() {return(0);}
|
||||||
|
double can_gate_time_offset() {return(0.0);}
|
||||||
|
|
||||||
|
unsigned long get_acckey() {return(0);}
|
||||||
|
|
||||||
|
static int shm_created=0;
|
||||||
|
|
||||||
|
/* to use _AFTER_ process forking */
|
||||||
|
void *init_can_io() { /* returns shared area addr. for client control process*/
|
||||||
|
int i;
|
||||||
|
int new_shm=0;
|
||||||
|
char *p, msg[100];
|
||||||
|
|
||||||
|
my_uid=geteuid();
|
||||||
|
if(can_shm_addr==NULL) {
|
||||||
|
if((p=strrchr(can_dev,'/'))!=NULL) {
|
||||||
|
memcpy(&can_lck[9], p+1, 4);
|
||||||
|
memcpy(can_shm_key.name, p+1, 4);
|
||||||
|
can_shm_key.name[4]='\0';
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"Wrong CAN device name: %s\n", can_dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
can_shm_id = shmget(can_shm_key.code, CAN_SHM_SIZE, 0644);
|
||||||
|
if(can_shm_id<0 && errno==EACCES)
|
||||||
|
can_shm_id = shmget(can_shm_key.code, CAN_SHM_SIZE, 0444);
|
||||||
|
if(can_shm_id<0 && errno==ENOENT && server_mode) {
|
||||||
|
can_shm_id = shmget(can_shm_key.code, CAN_SHM_SIZE, IPC_CREAT|IPC_EXCL|0644);
|
||||||
|
new_shm = shm_created = 1;
|
||||||
|
}
|
||||||
|
if(can_shm_id<0) {
|
||||||
|
can_prtime(stderr);
|
||||||
|
if(new_shm)
|
||||||
|
sprintf(msg,"Can't create shm CAN buffer '%s'",can_shm_key.name);
|
||||||
|
else if(server_mode)
|
||||||
|
sprintf(msg,"CAN-I/O: Can't find shm segment for CAN buffer '%s'",can_shm_key.name);
|
||||||
|
else
|
||||||
|
sprintf(msg,"Can't find shm segment for CAN buffer '%s' (maybe no CAN-I/O process?)",can_shm_key.name);
|
||||||
|
perror(msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
can_shm_addr = shmat(can_shm_id, NULL, 0);
|
||||||
|
if (can_shm_addr == (void*)-1 && errno==EACCES)
|
||||||
|
can_shm_addr = shmat(can_shm_id, NULL, SHM_RDONLY);
|
||||||
|
if (can_shm_addr == (void*)-1) {
|
||||||
|
sprintf(msg,"Can't attach shm CAN buffer '%s'",can_shm_key.name);
|
||||||
|
perror(msg);
|
||||||
|
shmctl(can_shm_id, IPC_RMID, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
can_ctrl_addr = (canmsg_t *)(can_shm_addr+sizeof(int)*3);
|
||||||
|
rx_buff = (canmsg_t *)(can_ctrl_addr+CAN_CTLR_SIZE);
|
||||||
|
|
||||||
|
if(can_fd<0 && canout.id<0) {
|
||||||
|
if(server_mode) {
|
||||||
|
if(( can_fd = open(can_dev, O_RDWR )) < 0 ) {
|
||||||
|
sprintf(msg,"CAN-I/O: Error opening CAN device %s", can_dev);
|
||||||
|
can_prtime(stderr);
|
||||||
|
perror(msg);
|
||||||
|
shmctl(can_shm_id, IPC_RMID, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if((canout.id = msgget(canout.key.code, canout.mode)) < 0) {
|
||||||
|
sprintf(msg,"Error opening CAN output queue '%s'(maybe no CANqueue server process?) ",canout.key.name);
|
||||||
|
perror(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(can_lk>0) close(can_lk);
|
||||||
|
if(( can_lk = open(can_lck, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH )) < 0 ) {
|
||||||
|
sprintf(msg,"Error opening CAN device lock-file %s", can_lck);
|
||||||
|
perror(msg);
|
||||||
|
shmctl(can_shm_id, IPC_RMID, NULL);
|
||||||
|
close(can_fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fchmod(can_lk, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||||
|
if(new_shm) {
|
||||||
|
struct timeval tmv;
|
||||||
|
struct timezone tz;
|
||||||
|
gettimeofday(&tmv,&tz);
|
||||||
|
if(flock(can_lk, LOCK_EX)<0) perror("locking CAN");
|
||||||
|
can_pid = 0;
|
||||||
|
can_open = -1;
|
||||||
|
rx_buff_pntr = 0;
|
||||||
|
for(i=0; i<CAN_RX_SIZE; i++) {
|
||||||
|
rx_buff[i].id = 0;
|
||||||
|
rx_buff[i].timestamp = tmv;
|
||||||
|
}
|
||||||
|
if(flock(can_lk, LOCK_UN)<0) perror("unlocking CAN");
|
||||||
|
}
|
||||||
|
signal(SIGHUP, can_exit);
|
||||||
|
signal(SIGINT, can_exit);
|
||||||
|
signal(SIGQUIT,can_exit);
|
||||||
|
signal(SIGTERM,can_exit);
|
||||||
|
return(can_ctrl_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CAN "Rx to buff" process */
|
||||||
|
void *start_can_io() {
|
||||||
|
|
||||||
|
set_server_mode(1);
|
||||||
|
init_can_io();
|
||||||
|
if(can_io_ok()) {
|
||||||
|
can_prtime(stderr);
|
||||||
|
fprintf(stderr,"CAN I/O process(%d) already running!\n",can_pid);
|
||||||
|
sleep(1);
|
||||||
|
can_prtime(stderr);
|
||||||
|
fprintf(stderr,"New CAN I/O process(%d) exiting...!\n",getpid());
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if( can_fd < 0 ) {
|
||||||
|
can_prtime(stderr);
|
||||||
|
fprintf(stderr,"Error opening CAN device %s\n", can_dev);
|
||||||
|
shmctl(can_shm_id, IPC_RMID, NULL);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
can_pid = getpid();
|
||||||
|
can_open = can_fd;
|
||||||
|
|
||||||
|
signal(SIGHUP, can_abort);
|
||||||
|
signal(SIGINT, can_abort);
|
||||||
|
signal(SIGQUIT,can_abort);
|
||||||
|
signal(SIGFPE, can_abort);
|
||||||
|
signal(SIGPIPE,can_abort);
|
||||||
|
signal(SIGSEGV,can_abort);
|
||||||
|
signal(SIGALRM, SIG_IGN);
|
||||||
|
signal(SIGTERM,can_abort);
|
||||||
|
|
||||||
|
if(shmctl(can_shm_id, SHM_LOCK, NULL) < 0)
|
||||||
|
perror("CAN I/O: can't prevents swapping of Rx-buffer area");
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
int n;
|
||||||
|
canmsg_t rx;
|
||||||
|
|
||||||
|
if(!can_io_shm_ok()) {can_delay(0.3); continue;}
|
||||||
|
|
||||||
|
n = can_wait(can_fd, 0.3);
|
||||||
|
if(n < 0) sleep(1);
|
||||||
|
if(n <= 0) continue;
|
||||||
|
|
||||||
|
// do {
|
||||||
|
static struct timeval tm = {0,0};
|
||||||
|
n = read(can_fd, &rx, sizeof(canmsg_t));
|
||||||
|
if(n < 0)
|
||||||
|
perror("CAN Rx error");
|
||||||
|
else if(n > 0) {
|
||||||
|
/* work around the timestamp bug in old driver version */
|
||||||
|
while((double)rx.timestamp.tv_sec+(double)rx.timestamp.tv_usec/1e6 < (double)tm.tv_sec+(double)tm.tv_usec/1e6) {
|
||||||
|
rx.timestamp.tv_usec += 10000;
|
||||||
|
if(rx.timestamp.tv_usec > 1000000) {
|
||||||
|
rx.timestamp.tv_sec++;
|
||||||
|
rx.timestamp.tv_usec -= 1000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(flock(can_lk, LOCK_EX)<0) perror("locking CAN");
|
||||||
|
rx_buff[rx_buff_pntr] = rx;
|
||||||
|
rx_buff_pntr = (rx_buff_pntr + 1) % CAN_RX_SIZE;
|
||||||
|
if(flock(can_lk, LOCK_UN)<0) perror("unlocking CAN");
|
||||||
|
//fprintf(stderr,"%d read(id=%02x,len=%d)\n",rx_buff_pntr,rx.id,rx.length);fflush(stderr);
|
||||||
|
/*fprintf(stderr,"reading CAN: 1 frame\n");*/
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"reading CAN: nothing\n");fflush(stderr);
|
||||||
|
}
|
||||||
|
// } while(n>0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put CAN-frame to recv-buffer */
|
||||||
|
void can_put_buff_frame(double rtime, int id, int length, unsigned char data[]) {
|
||||||
|
int i;
|
||||||
|
canmsg_t rx;
|
||||||
|
int sec = (int)rtime;
|
||||||
|
if(!server_mode) return;
|
||||||
|
if(length<0) length=0;
|
||||||
|
if(length>8) length=8;
|
||||||
|
rx.id=id;
|
||||||
|
rx.length=length;
|
||||||
|
for(i=0; i<length; i++) rx.data[i]=data[i];
|
||||||
|
rx.timestamp.tv_sec = sec;
|
||||||
|
rx.timestamp.tv_usec = (int)((rtime-sec)*1000000.);
|
||||||
|
if(flock(can_lk, LOCK_EX)<0) perror("locking CAN");
|
||||||
|
rx_buff[rx_buff_pntr] = rx;
|
||||||
|
rx_buff_pntr = (rx_buff_pntr + 1) % CAN_RX_SIZE;
|
||||||
|
if(flock(can_lk, LOCK_UN)<0) perror("unlocking CAN");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ÷ÓÅ ÎÏÒÍÁÌØÎÏ Ó SHM-ÂÕÆÅÒÏÍ CAN-I/O ÐÒÏÃÅÓÓÁ */
|
||||||
|
int can_io_shm_ok() {
|
||||||
|
return(can_pid>0 && can_open>0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ÷ÓÅ ÎÏÒÍÁÌØÎÏ Ó CAN-I/O ÐÒÏÃÅÓÓÏÍ */
|
||||||
|
/* (ÎÏ ÎÁÄÏ ÂÙÔØ ÓÕÐÅÒ-ÀÚÅÒÏÍ!) */
|
||||||
|
int can_io_ok() {
|
||||||
|
return(can_io_shm_ok() && (my_uid!=0||kill(can_pid, 0)==0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ÷ÏÚÍÏÖÎÁ ÒÁÂÏÔÁ c CAN ÄÌÑ ËÌÉÅÎÔÁ */
|
||||||
|
int can_ok() {
|
||||||
|
return(can_io_shm_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* wait for CAN-frame */
|
||||||
|
int can_wait(int fd, double tout)
|
||||||
|
{
|
||||||
|
int nfd,width;
|
||||||
|
struct timeval tv;
|
||||||
|
fd_set readfds;
|
||||||
|
|
||||||
|
if(fd==0 && tout>=0.01) {
|
||||||
|
double dt = can_dsleep(tout);
|
||||||
|
if(dt>0.) can_dsleep(dt);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
if(fd<0) fd=can_fd;
|
||||||
|
if(fd>0) {
|
||||||
|
FD_ZERO(&readfds);
|
||||||
|
FD_SET(fd, &readfds);
|
||||||
|
width = fd+1;
|
||||||
|
} else
|
||||||
|
width = 0;
|
||||||
|
tv.tv_sec = (int)tout;
|
||||||
|
tv.tv_usec = (int)((tout - tv.tv_sec)*1000000.+0.9);
|
||||||
|
slipping:
|
||||||
|
if(fd>0 && can_fd>0)
|
||||||
|
nfd = select(width, &readfds, (fd_set *)NULL, (fd_set *)NULL, &tv);
|
||||||
|
else
|
||||||
|
nfd = select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &tv);
|
||||||
|
if(nfd < 0) {
|
||||||
|
if(errno == EINTR)
|
||||||
|
goto slipping;
|
||||||
|
perror("Error in can_wait(){ select() }");
|
||||||
|
return(-1);
|
||||||
|
} else if(nfd == 0) /* timeout! */
|
||||||
|
return(0);
|
||||||
|
if(fd>0 && FD_ISSET(fd, &readfds)) /* Rx frame! */
|
||||||
|
return(1);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cleanup recv-buffer in client process */
|
||||||
|
void can_clean_recv(int *pbuf, double *rtime) {
|
||||||
|
struct timeval tmv;
|
||||||
|
struct timezone tz;
|
||||||
|
gettimeofday(&tmv,&tz);
|
||||||
|
*pbuf = rx_buff_pntr;
|
||||||
|
*rtime = tmv.tv_sec + (double)tmv.tv_usec/1000000.;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find next rx-frame in recv-buffer for client process */
|
||||||
|
int can_recv_frame(int *pbuf, double *rtime,
|
||||||
|
int *id, int *length, unsigned char data[]) {
|
||||||
|
return(can_get_buff_frame(pbuf, rtime, id, length, data));
|
||||||
|
}
|
||||||
|
int can_get_buff_frame(int *pbuf, double *rtime,
|
||||||
|
int *id, int *length, unsigned char data[]) {
|
||||||
|
while(*pbuf != rx_buff_pntr) {
|
||||||
|
canmsg_t *rx = &rx_buff[*pbuf];
|
||||||
|
struct timeval *tv = &rx->timestamp;
|
||||||
|
double t_rx;
|
||||||
|
|
||||||
|
if(flock(can_lk, LOCK_EX)<0) perror("locking CAN");
|
||||||
|
|
||||||
|
t_rx = tv->tv_sec + (double)tv->tv_usec/1000000.;
|
||||||
|
if(t_rx+1. >= *rtime) {
|
||||||
|
int i;
|
||||||
|
*id = rx->id;
|
||||||
|
*length = rx->length;
|
||||||
|
for(i = 0; i < *length; i++)
|
||||||
|
data[i] = rx->data[i];
|
||||||
|
*rtime = t_rx;
|
||||||
|
*pbuf = (*pbuf + 1) % CAN_RX_SIZE;
|
||||||
|
|
||||||
|
if(flock(can_lk, LOCK_UN)<0) perror("unlocking CAN");
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
*pbuf = (*pbuf + 1) % CAN_RX_SIZE;
|
||||||
|
|
||||||
|
if(flock(can_lk, LOCK_UN)<0) perror("unlocking CAN");
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send tx-frame from client process */
|
||||||
|
/* to CAN-driver or to output queue */
|
||||||
|
int can_send_frame(int id, int length, unsigned char data[]) {
|
||||||
|
int i, ret=1;
|
||||||
|
if(can_fd<0 && canout.id<0)
|
||||||
|
return(0);
|
||||||
|
if(length>8) length=8;
|
||||||
|
if(length<0) length=0;
|
||||||
|
if(can_fd>=0) {
|
||||||
|
canmsg_t tx;
|
||||||
|
tx.id=id;
|
||||||
|
tx.cob=0;
|
||||||
|
tx.flags=0;
|
||||||
|
tx.length=length;
|
||||||
|
for(i=0;i<length;i++) tx.data[i]=data[i];
|
||||||
|
if(flock(can_lk, LOCK_EX)<0) perror("locking CAN");
|
||||||
|
ret = write(can_fd, &tx, sizeof(canmsg_t));
|
||||||
|
if(flock(can_lk, LOCK_UN)<0) perror("unlocking CAN");
|
||||||
|
if(server_mode)
|
||||||
|
/* copy tx CAN-frame back to recv-buffer */
|
||||||
|
can_put_buff_frame(can_dtime(), id, length, data);
|
||||||
|
} else if(canout.id>=0) {
|
||||||
|
struct my_msgbuf mbuf;
|
||||||
|
mbuf.src_pid = getpid();
|
||||||
|
mbuf.src_ip = 0;
|
||||||
|
mbuf.acckey = canout.acckey;
|
||||||
|
mbuf.mtype = id;
|
||||||
|
for(i=0;i<length;i++) mbuf.mtext[i]=data[i];
|
||||||
|
msgsnd( canout.id, (struct msgbuf *)&mbuf, length+12, IPC_NOWAIT);
|
||||||
|
}
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void can_abort(int sig) {
|
||||||
|
char ss[10];
|
||||||
|
struct shmid_ds buf;
|
||||||
|
|
||||||
|
if(sig) signal(sig,SIG_IGN);
|
||||||
|
if(!server_mode) can_exit(sig);
|
||||||
|
switch (sig) {
|
||||||
|
case 0 : strcpy(ss," "); break;
|
||||||
|
case SIGHUP : strcpy(ss,"SIGHUP -"); break;
|
||||||
|
case SIGINT : strcpy(ss,"SIGINT -"); break;
|
||||||
|
case SIGQUIT: strcpy(ss,"SIGQUIT -"); break;
|
||||||
|
case SIGFPE : strcpy(ss,"SIGFPE -"); break;
|
||||||
|
case SIGPIPE: strcpy(ss,"SIGPIPE -"); break;
|
||||||
|
case SIGSEGV: strcpy(ss,"SIGSEGV -"); break;
|
||||||
|
case SIGTERM: strcpy(ss,"SIGTERM -"); break;
|
||||||
|
default: sprintf(ss,"SIG_%d -",sig); break;
|
||||||
|
}
|
||||||
|
switch (sig) {
|
||||||
|
default:
|
||||||
|
case SIGHUP :
|
||||||
|
case SIGINT :
|
||||||
|
can_prtime(stderr);
|
||||||
|
fprintf(stderr,"CAN I/O: %s Ignore .....\n",ss);
|
||||||
|
fflush(stderr);
|
||||||
|
signal(sig, can_abort);
|
||||||
|
return;
|
||||||
|
case SIGPIPE:
|
||||||
|
case SIGQUIT:
|
||||||
|
case SIGFPE :
|
||||||
|
case SIGSEGV:
|
||||||
|
case SIGTERM:
|
||||||
|
signal(SIGALRM, can_abort);
|
||||||
|
alarm(2);
|
||||||
|
can_prtime(stderr);
|
||||||
|
fprintf(stderr,"CAN I/O: %s process should stop after 2sec delay...\n",ss);
|
||||||
|
fflush(stderr);
|
||||||
|
close(can_fd);
|
||||||
|
can_fd = can_open = -1;
|
||||||
|
return;
|
||||||
|
case SIGALRM:
|
||||||
|
can_prtime(stderr);
|
||||||
|
fprintf(stderr,"CAN I/O: process stop!\n");
|
||||||
|
fflush(stderr);
|
||||||
|
close(can_lk);
|
||||||
|
can_lk = -1;
|
||||||
|
can_pid = 0;
|
||||||
|
shmdt(can_shm_addr);
|
||||||
|
shmctl(can_shm_id, IPC_STAT, &buf);
|
||||||
|
if(buf.shm_nattch==0) {
|
||||||
|
shmctl(can_shm_id, SHM_UNLOCK, NULL);
|
||||||
|
shmctl(can_shm_id, IPC_RMID, NULL);
|
||||||
|
}
|
||||||
|
exit(sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void can_exit(int sig) {
|
||||||
|
char ss[12];
|
||||||
|
|
||||||
|
struct shmid_ds buf;
|
||||||
|
if(sig) signal(sig,SIG_IGN);
|
||||||
|
if(server_mode) can_abort(sig);
|
||||||
|
switch (sig) {
|
||||||
|
case 0 : strcpy(ss,"Exiting - "); break;
|
||||||
|
case SIGHUP : strcpy(ss,"SIGHUP -"); break;
|
||||||
|
case SIGINT : strcpy(ss,"SIGINT -"); break;
|
||||||
|
case SIGQUIT: strcpy(ss,"SIGQUIT -"); break;
|
||||||
|
case SIGFPE : strcpy(ss,"SIGFPE -"); break;
|
||||||
|
case SIGPIPE: strcpy(ss,"SIGPIPE -"); break;
|
||||||
|
case SIGSEGV: strcpy(ss,"SIGSEGV -"); break;
|
||||||
|
case SIGTERM: strcpy(ss,"SIGTERM -"); break;
|
||||||
|
default: sprintf(ss,"SIG_%d -",sig); break;
|
||||||
|
}
|
||||||
|
switch (sig) {
|
||||||
|
default:
|
||||||
|
case SIGHUP :
|
||||||
|
can_prtime(stderr);
|
||||||
|
fprintf(stderr,"%s Ignore .....\n",ss);
|
||||||
|
fflush(stderr);
|
||||||
|
signal(sig, can_exit);
|
||||||
|
return;
|
||||||
|
case 0:
|
||||||
|
case SIGINT :
|
||||||
|
case SIGPIPE:
|
||||||
|
case SIGQUIT:
|
||||||
|
case SIGFPE :
|
||||||
|
case SIGSEGV:
|
||||||
|
case SIGTERM:
|
||||||
|
if(can_fd>=0) close(can_fd);
|
||||||
|
can_prtime(stderr);
|
||||||
|
fprintf(stderr,"%s process stop!\n",ss);
|
||||||
|
fflush(stderr);
|
||||||
|
close(can_lk);
|
||||||
|
shmdt(can_shm_addr);
|
||||||
|
shmctl(can_shm_id, IPC_STAT, &buf);
|
||||||
|
if(buf.shm_nattch==0)
|
||||||
|
shmctl(can_shm_id, IPC_RMID, NULL);
|
||||||
|
exit(sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *time2asc(double t)
|
||||||
|
{
|
||||||
|
static char stmp[10][20];
|
||||||
|
static int itmp=0;
|
||||||
|
char *lin = stmp[itmp];
|
||||||
|
int h, min;
|
||||||
|
double sec;
|
||||||
|
h = (int)(t/3600.);
|
||||||
|
min = (int)((t - (double)h*3600.)/60.);
|
||||||
|
sec = t - (double)h*3600. - (double)min*60.;
|
||||||
|
h %= 24;
|
||||||
|
sprintf(lin, "%02d:%02d:%09.6f", h,min,sec);
|
||||||
|
itmp = (itmp+1)%10;
|
||||||
|
return lin;
|
||||||
|
}
|
||||||
|
|
||||||
|
double can_dsleep(double dt) {
|
||||||
|
struct timespec ts,tsr;
|
||||||
|
ts.tv_sec = (time_t)dt;
|
||||||
|
ts.tv_nsec = (long)((dt-ts.tv_sec)*1e9);
|
||||||
|
nanosleep(&ts,&tsr);
|
||||||
|
return((double)ts.tv_sec + (double)ts.tv_nsec/1e9);
|
||||||
|
}
|
||||||
|
|
||||||
|
double can_dtime() {
|
||||||
|
struct timeval ct;
|
||||||
|
struct timezone tz;
|
||||||
|
gettimeofday(&ct, &tz);
|
||||||
|
return ((double)ct.tv_sec + (double)ct.tv_usec/1e6);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *can_atime() {return(time2asc(can_dtime()));}
|
||||||
|
|
||||||
|
void can_prtime(FILE *fd) {
|
||||||
|
static double otime=0.0;
|
||||||
|
double ntime=can_dtime();
|
||||||
|
time_t itime = (int)ntime;
|
||||||
|
if(otime==0.0) tzset();
|
||||||
|
ntime -= (double)timezone;
|
||||||
|
if((((int)ntime)%(24*3600) < ((int)otime)%(24*3600)) || otime==0.0)
|
||||||
|
fprintf(fd,"========================\n%s",ctime(&itime));
|
||||||
|
fprintf(fd,"%s ",time2asc(ntime));
|
||||||
|
otime=ntime;
|
||||||
|
}
|
||||||
29
Socket_CAN/can_io.h
Normal file
29
Socket_CAN/can_io.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#define CAN_CTLR_SIZE 300 /* size of client process shared area */
|
||||||
|
#define CAN_RX_SIZE 1000 /* max. # frames in Rx-buffer */
|
||||||
|
|
||||||
|
int can_wait(int fd, double tout);
|
||||||
|
#define can_delay(Tout) can_wait(0, Tout)
|
||||||
|
void set_server_mode(int mode);
|
||||||
|
int can_server();
|
||||||
|
int can_card();
|
||||||
|
int can_gate();
|
||||||
|
double can_gate_time_offset();
|
||||||
|
unsigned long get_acckey();
|
||||||
|
void *init_can_io();
|
||||||
|
void *start_can_io();
|
||||||
|
void can_put_buff_frame(double rtime, int id, int length, unsigned char data[]);
|
||||||
|
int can_io_ok();
|
||||||
|
int can_io_shm_ok();
|
||||||
|
int can_ok();
|
||||||
|
void can_clean_recv(int *pbuf, double *rtime);
|
||||||
|
int can_get_buff_frame(int *pbuf, double *rtime,
|
||||||
|
int *id, int *length, unsigned char data[]);
|
||||||
|
int can_recv_frame(int *pbuf, double *rtime,
|
||||||
|
int *id, int *length, unsigned char data[]);
|
||||||
|
int can_send_frame(int id, int length, unsigned char data[]);
|
||||||
|
void can_exit(int sig);
|
||||||
|
char *time2asc(double t);
|
||||||
|
double can_dsleep(double dt);
|
||||||
|
double can_dtime();
|
||||||
|
char *can_atime();
|
||||||
|
void can_prtime(FILE *fd);
|
||||||
39
Socket_CAN/canbus.h
Normal file
39
Socket_CAN/canbus.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef CANBUS_H__
|
||||||
|
#define CANBUS_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// CAN packet MAGICK
|
||||||
|
#define CANMAGICK (0xdeadbeef)
|
||||||
|
// BTA SEW mask
|
||||||
|
#define ID_MASK (0xD80)
|
||||||
|
// BTA SEW-dome frames
|
||||||
|
#define ID_DOME (0x580)
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
uint32_t magick;
|
||||||
|
uint16_t ID;
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t data[8];
|
||||||
|
} can_packet;
|
||||||
|
|
||||||
|
#endif // CANBUS_H__
|
||||||
76
Socket_CAN/cansock.c
Normal file
76
Socket_CAN/cansock.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
int readCAN(int sock, struct can_frame *frame){
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 1000; // wait not more than 1millisecond
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(sock, &fds);
|
||||||
|
do{
|
||||||
|
int rc = select(sock+1, &fds, NULL, NULL, &timeout);
|
||||||
|
if(rc < 0){
|
||||||
|
if(errno != EINTR){
|
||||||
|
WARN("select()");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}while(1);
|
||||||
|
if(FD_ISSET(sock, &fds)){
|
||||||
|
return read(sock, frame, sizeof(struct can_frame));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||||
|
if(sock < 0) ERR("Can't create socket");
|
||||||
|
struct sockaddr_can addr;
|
||||||
|
struct ifreq ifr;
|
||||||
|
strcpy(ifr.ifr_name, "can0");
|
||||||
|
if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0) ERR("ioctl()");
|
||||||
|
addr.can_family = AF_CAN;
|
||||||
|
addr.can_ifindex = ifr.ifr_ifindex;
|
||||||
|
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) ERR("bind()");
|
||||||
|
int nbytes = 0;
|
||||||
|
struct can_frame frame = {0};
|
||||||
|
double dt = dtime();
|
||||||
|
do{
|
||||||
|
nbytes = readCAN(sock, &frame);
|
||||||
|
if(nbytes < 0) ERR("can raw socket read");
|
||||||
|
}while(nbytes == 0 && dtime() - dt < 10.);
|
||||||
|
printf("got frame len=%d id=%d", frame.can_dlc, frame.can_id);
|
||||||
|
if(frame.can_dlc) printf(", data: ");
|
||||||
|
for(int i = 0; i < frame.can_dlc; ++i)
|
||||||
|
printf("0x%02x ", frame.data[i]);
|
||||||
|
printf("\n");
|
||||||
|
frame.can_dlc = 6;
|
||||||
|
frame.can_id = 0xaa;
|
||||||
|
const uint8_t d[] = {1, 2, 3, 4, 5, 6, 0, 0};
|
||||||
|
memcpy(&frame.data, d, 8);
|
||||||
|
int n = write(sock, &frame, sizeof(struct can_frame));
|
||||||
|
if(sizeof(struct can_frame) != n){
|
||||||
|
printf("n=%d\n", n);
|
||||||
|
WARN("write()");
|
||||||
|
}
|
||||||
|
close(sock);
|
||||||
28
Socket_CAN/cert.key
Normal file
28
Socket_CAN/cert.key
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCocrggX/uMcOfG
|
||||||
|
bVqeVZpqzX/RPl0YZf9R5ym0YhCeZPj4Ribl59vLsjFShR0PtwV3pCffZUazQJHs
|
||||||
|
yA/UxrIG3JN9sk5B3+SdBUdmFDXcjI/vTYAFjqa6cqQ7GqQENNSKnvIW2PWe+TS8
|
||||||
|
KepPQKEqdXLb2k7MTTLx7sFeS3RyNHnQ9V1Ef7ZTjmYGrGe6QQA1irf3QgZ8c47Q
|
||||||
|
oIUQBEIj1JFyXhChU15BRwVEcAGDrcp8QCYjSba8ac+eBDmn/c8Ojrw3MIsgB38q
|
||||||
|
I18xXIfuf4jSN+hZjMktFr/IZwePOUFqQjSNkMlUsZvUdkFWfEoEamP3b5Pft1IC
|
||||||
|
okeg4+rDAgMBAAECggEAYHRoOKmdadrQ7Q97H0UXSeboNNHIDwuAus5qVA7/QyPA
|
||||||
|
aLIK3gT5F9euZHkynegIKm0GI+ZjKItlw7b/UbCBCmrNzeEG7LOevcbjDnGuMd8P
|
||||||
|
IFE5aHU5xXOV1P45QutZdRL0vt53LxO1/bTmpYD1iFF+dqO4EUZ3UI+NjEgaorW5
|
||||||
|
x9kZwV6PE4Cnfcx8kdDNvBrQDs/AXJz3zNNsIU7cEFAVLvtkDnw5+aa0O52lLa+D
|
||||||
|
2vtpctxCyPrKtV5Z7Cgd+KkvXKDYbSgrld/Pb6Bhwj+cD39s5Jd/JRBnhpprHq5Y
|
||||||
|
X8nCs0rZP901rTbGPRcOAu1qUrgdtEyFyiAMnCBGWQKBgQDWQGD87w2E7cbNxZAp
|
||||||
|
nYBc4LizChtvFRu5hDmbblhvRt93XWh4H5wrJuKbFBM/O38KHy/9GCEVv8XwCkgd
|
||||||
|
DKhNlAPwMkszxYkVw4cmc3FwKEQhfX4KpzwfrWFbPFTGlCtt3EAP5g6wvXYJeWZZ
|
||||||
|
T+KXCOzWG5b+v38LLZzxctPp7QKBgQDJRYHKK4txrbXIfqSILk1k9C3+8H6lPFfk
|
||||||
|
S0gemPP7TuE2jHH/OsK36qtgH+i6pWrqZVKL9QmpFugiSvI/SP0DWk7t17iFnJ6s
|
||||||
|
bltn8gftASRnx8yFVZBYUO9TbmriS0ZRJG8Yz7f79jj2TGDunBVgeu560X6Syjyk
|
||||||
|
WpzEjEPRbwKBgFL2MNggNOrxK5cIVi9XFppgRgTF+COGV+r5IVlnXAUSu3s8BzTk
|
||||||
|
gJNRBlQobN+CSUoBE5L8YetLC/lL8eqVuSH5G6FJyEbuyYtM4CtqblWQsfkJ3+F+
|
||||||
|
KlDV0SoD7YvLWhm7PG8rlSqo4mj+wjv5K/Nx+Etb+ZcBTc9lRS1VWmttAoGBAMSC
|
||||||
|
GnA7B5Bb26n/C8DyBBpW1TmdsOi++8knPyiwiTWKFBTgFsTsqARNGDlnrh/dNX/Y
|
||||||
|
oTmIaoAun0IsDkx/hJfrajiJb9zzx2/u50ubYOWjQdoZlrNvkNjJXIEGw1Bh0iuS
|
||||||
|
+O0ukSFtirveYp1UwwJJw+Eh/QRwc7i7x2eW0vf9AoGAVPIZuGkwafu4yfsKBKqx
|
||||||
|
Qvmgm7+iCywBz6jj70Zk1uS2+l/Kvc1sFD3vF9QS6LzxWgotMqqTR+JTLqMhw/SW
|
||||||
|
nTSoickIlkchWWnOF0tg1Gx9qHj9iTXufSwAqtYa18Srf/lQKB/HM24BSugGAxK/
|
||||||
|
W+UrzBJIZnVyR/HkDSk5VWY=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
21
Socket_CAN/cert.pem
Normal file
21
Socket_CAN/cert.pem
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDXzCCAkegAwIBAgIUBo309dQtnbIqVJIYQ0929yXmRB0wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwPzELMAkGA1UEBhMCUlUxDTALBgNVBAgMBEtDaFIxDzANBgNVBAcMBkJ1a292
|
||||||
|
bzEQMA4GA1UECgwHU0FPIFJBUzAeFw0yMTEyMTYwODA3NDNaFw00OTA4MTEwODA3
|
||||||
|
NDNaMD8xCzAJBgNVBAYTAlJVMQ0wCwYDVQQIDARLQ2hSMQ8wDQYDVQQHDAZCdWtv
|
||||||
|
dm8xEDAOBgNVBAoMB1NBTyBSQVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||||
|
AoIBAQCocrggX/uMcOfGbVqeVZpqzX/RPl0YZf9R5ym0YhCeZPj4Ribl59vLsjFS
|
||||||
|
hR0PtwV3pCffZUazQJHsyA/UxrIG3JN9sk5B3+SdBUdmFDXcjI/vTYAFjqa6cqQ7
|
||||||
|
GqQENNSKnvIW2PWe+TS8KepPQKEqdXLb2k7MTTLx7sFeS3RyNHnQ9V1Ef7ZTjmYG
|
||||||
|
rGe6QQA1irf3QgZ8c47QoIUQBEIj1JFyXhChU15BRwVEcAGDrcp8QCYjSba8ac+e
|
||||||
|
BDmn/c8Ojrw3MIsgB38qI18xXIfuf4jSN+hZjMktFr/IZwePOUFqQjSNkMlUsZvU
|
||||||
|
dkFWfEoEamP3b5Pft1ICokeg4+rDAgMBAAGjUzBRMB0GA1UdDgQWBBRqwlIH5zOT
|
||||||
|
171ywLEMmP1WfJ3ZdjAfBgNVHSMEGDAWgBRqwlIH5zOT171ywLEMmP1WfJ3ZdjAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAwgUv4mlGxwqmyQsTg
|
||||||
|
LHVppuLl4TA1EMrUuvJfSBClfStnWiCDJmNMn7OMAuNVmpLZHz2gPbAz5fHRnm0N
|
||||||
|
Ey3nQNS0X18/jq4NCjaONoSjcRxHDbw0V0E2Kap+t9YZbzw83FWKcJM3WKMAL51p
|
||||||
|
xiUWQ9bP5E7CFY+j+kcty3HfSgoGcEqanTK94QQqlKxczI1kKkR/Bdow3jTk6PG7
|
||||||
|
fMPU6c8FL3NkRacKGoc5VNq8A7HI5Hll4gu1fYxXVYnkKc45NrLsipdhInFNJOmx
|
||||||
|
O16CWm+S/YEJFVio6Eke9FhLehaHagY0oMhadaV4sxtTDXGosfoI/XorGsYE79sU
|
||||||
|
uqgK
|
||||||
|
-----END CERTIFICATE-----
|
||||||
43
Socket_CAN/client.c
Normal file
43
Socket_CAN/client.c
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <linux/can.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "daemon.h"
|
||||||
|
#include "sslsock.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv){
|
||||||
|
char *self = argv[0];
|
||||||
|
initial_setup();
|
||||||
|
parse_args(argc, argv);
|
||||||
|
// check args
|
||||||
|
if(!G.serverhost) ERR("Point server IP address");
|
||||||
|
#ifdef EBUG
|
||||||
|
printf("Server: %s\n", G.serverhost);
|
||||||
|
#endif
|
||||||
|
return start_daemon(self);
|
||||||
|
}
|
||||||
24
Socket_CAN/client.h
Normal file
24
Socket_CAN/client.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#ifndef CLIENT_H__
|
||||||
|
#define CLIENT_H__
|
||||||
|
|
||||||
|
#include "canbus.h"
|
||||||
|
|
||||||
|
#endif // CLIENT_H__
|
||||||
89
Socket_CAN/cmdlnopts.c
Normal file
89
Socket_CAN/cmdlnopts.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* here are global parameters initialisation
|
||||||
|
*/
|
||||||
|
static int help;
|
||||||
|
glob_pars G;
|
||||||
|
|
||||||
|
// DEFAULTS
|
||||||
|
// default global parameters
|
||||||
|
static glob_pars const Gdefault = {
|
||||||
|
.pidfile = DEFAULT_PIDFILE,
|
||||||
|
.port = DEFAULT_PORT,
|
||||||
|
.cert = "cert.pem",
|
||||||
|
.key = "cert.key",
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define command line options by filling structure:
|
||||||
|
* name has_arg flag val type argptr help
|
||||||
|
*/
|
||||||
|
static myoption cmdlnopts[] = {
|
||||||
|
// common options
|
||||||
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")},
|
||||||
|
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), _("file to save logs")},
|
||||||
|
{"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")},
|
||||||
|
{"certificate",NEED_ARG,NULL, 'c', arg_string, APTR(&G.cert), _("path to SSL sertificate (default: cert.pem)")},
|
||||||
|
{"key", NEED_ARG, NULL, 'k', arg_string, APTR(&G.key), _("path to SSL key (default: cert.key)")},
|
||||||
|
{"ca", NEED_ARG, NULL, 'a', arg_string, APTR(&G.ca), _("path to SSL ca (default: ca.pem)")},
|
||||||
|
{"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), _("port to open (default: " DEFAULT_PORT ")")},
|
||||||
|
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), _("increase log verbose level (default: LOG_WARN)")},
|
||||||
|
#ifdef SERVER
|
||||||
|
#endif
|
||||||
|
#ifdef CLIENT
|
||||||
|
{"server", NEED_ARG, NULL, 'i', arg_string, APTR(&G.serverhost), _("server IP address")},
|
||||||
|
#endif
|
||||||
|
end_option
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse command line options and return dynamically allocated structure
|
||||||
|
* to global parameters
|
||||||
|
* @param argc - copy of argc from main
|
||||||
|
* @param argv - copy of argv from main
|
||||||
|
*/
|
||||||
|
void parse_args(int argc, char **argv){
|
||||||
|
int i;
|
||||||
|
void *ptr;
|
||||||
|
ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr);
|
||||||
|
size_t hlen = 1024;
|
||||||
|
char helpstring[1024], *hptr = helpstring;
|
||||||
|
snprintf(hptr, hlen, "Usage: %%s [args]\n\n\tWhere args are:\n");
|
||||||
|
// format of help: "Usage: progname [args]\n"
|
||||||
|
change_helpstring(helpstring);
|
||||||
|
// parse arguments
|
||||||
|
parseargs(&argc, &argv, cmdlnopts);
|
||||||
|
if(help) showhelp(-1, cmdlnopts);
|
||||||
|
if(argc > 0){
|
||||||
|
red("Ignored options:\n");
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
printf("\t%s\n", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
54
Socket_CAN/cmdlnopts.h
Normal file
54
Socket_CAN/cmdlnopts.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef CMDLNOPTS_H__
|
||||||
|
#define CMDLNOPTS_H__
|
||||||
|
|
||||||
|
// default PID filename:
|
||||||
|
#ifndef DEFAULT_PIDFILE
|
||||||
|
#define DEFAULT_PIDFILE "/tmp/soccan.pid"
|
||||||
|
#endif
|
||||||
|
#ifndef DEFAULT_PORT
|
||||||
|
#define DEFAULT_PORT "4444"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* here are some typedef's for global data
|
||||||
|
*/
|
||||||
|
typedef struct{
|
||||||
|
char *pidfile; // name of PID file
|
||||||
|
char *logfile; // logging to this file
|
||||||
|
char *cert; // sertificate
|
||||||
|
char *key; // key
|
||||||
|
char *ca; // ca
|
||||||
|
char *port; // port number
|
||||||
|
int verbose; // logfile verbose level
|
||||||
|
#ifdef SERVER
|
||||||
|
#endif
|
||||||
|
#ifdef CLIENT
|
||||||
|
char *serverhost; // server IP address
|
||||||
|
int speed; // connection speed
|
||||||
|
#endif
|
||||||
|
} glob_pars;
|
||||||
|
|
||||||
|
extern glob_pars G;
|
||||||
|
|
||||||
|
void parse_args(int argc, char **argv);
|
||||||
|
|
||||||
|
#endif // CMDLNOPTS_H__
|
||||||
99
Socket_CAN/daemon.c
Normal file
99
Socket_CAN/daemon.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/prctl.h> // prctl
|
||||||
|
#include <sys/wait.h> // wait
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "daemon.h"
|
||||||
|
#include "sslsock.h"
|
||||||
|
|
||||||
|
static pid_t childpid = 0;
|
||||||
|
|
||||||
|
void signals(int sig){
|
||||||
|
if(childpid == 0){
|
||||||
|
LOGWARN("Child killed with sig=%d", sig);
|
||||||
|
exit(sig); // slave process
|
||||||
|
}
|
||||||
|
// master process
|
||||||
|
if(sig){
|
||||||
|
signal(sig, SIG_IGN);
|
||||||
|
LOGERR("Exit with signal %d", sig);
|
||||||
|
}else LOGERR("Exit");
|
||||||
|
if(G.pidfile) unlink(G.pidfile);
|
||||||
|
exit(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief start_daemon - daemonize
|
||||||
|
* @param self - self name of process
|
||||||
|
* @return error code or 0
|
||||||
|
*/
|
||||||
|
int start_daemon(_U_ char *self){
|
||||||
|
// check args
|
||||||
|
int port = atoi(G.port);
|
||||||
|
if(port < 1024 || port > 65535){
|
||||||
|
LOGERR("Wrong port value: %d", port);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
FILE *f = fopen(G.cert, "r");
|
||||||
|
if(!f) ERR("Can't open certificate file %s", G.cert);
|
||||||
|
fclose(f);
|
||||||
|
f = fopen(G.key, "r");
|
||||||
|
if(!f) ERR("Can't open certificate key file %s", G.key);
|
||||||
|
fclose(f);
|
||||||
|
#ifdef EBUG
|
||||||
|
printf("cert: %s, key: %s\n", G.cert, G.key);
|
||||||
|
#endif
|
||||||
|
if(G.logfile){
|
||||||
|
int lvl = LOGLEVEL_WARN + G.verbose;
|
||||||
|
DBG("level = %d", lvl);
|
||||||
|
if(lvl > LOGLEVEL_ANY) lvl = LOGLEVEL_ANY;
|
||||||
|
green("Log file %s @ level %d\n", G.logfile, lvl);
|
||||||
|
OPENLOG(G.logfile, lvl, 1);
|
||||||
|
}
|
||||||
|
signal(SIGTERM, signals); // kill (-15) - quit
|
||||||
|
signal(SIGHUP, SIG_IGN); // hup - ignore
|
||||||
|
signal(SIGINT, signals); // ctrl+C - quit
|
||||||
|
signal(SIGQUIT, signals); // ctrl+\ - quit
|
||||||
|
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
||||||
|
#ifdef SERVER
|
||||||
|
check4running(self, G.pidfile);
|
||||||
|
#endif
|
||||||
|
LOGMSG("Started");
|
||||||
|
#ifndef EBUG
|
||||||
|
while(1){
|
||||||
|
childpid = fork();
|
||||||
|
if(childpid){ // master
|
||||||
|
LOGMSG("Created child with pid %d", childpid);
|
||||||
|
wait(NULL);
|
||||||
|
LOGWARN("Child %d died", childpid);
|
||||||
|
sleep(1); // wait a little before respawn
|
||||||
|
}else{ // slave
|
||||||
|
prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// parent should never reach this part of code
|
||||||
|
return open_socket();
|
||||||
|
}
|
||||||
25
Socket_CAN/daemon.h
Normal file
25
Socket_CAN/daemon.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef DAEMON_H__
|
||||||
|
#define DAEMON_H__
|
||||||
|
|
||||||
|
int start_daemon(char *self);
|
||||||
|
|
||||||
|
#endif // DAEMON_H__
|
||||||
5
Socket_CAN/diff/clientscript
Executable file
5
Socket_CAN/diff/clientscript
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
for ((x=0; x<10; ++x)); do
|
||||||
|
socat TCP-LISTEN:2000 PTY,link=/tmp/ttyX0,raw,crnl
|
||||||
|
done
|
||||||
6
Socket_CAN/diff/serverscript
Executable file
6
Socket_CAN/diff/serverscript
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#for ((x=0; x<10; ++x)); do
|
||||||
|
socat pty,link=/tmp/ttyX0,waitslave tcp:127.0.0.1:2002 &
|
||||||
|
ssh -L 2002:robotel1:2000 -N -f robotel1
|
||||||
|
#done
|
||||||
121
Socket_CAN/log.log
Normal file
121
Socket_CAN/log.log
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
[ERR] 2021/12/20-09:51:56 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-09:51:57 SSL_accept()
|
||||||
|
[WARN] 2021/12/20-09:51:57 Child killed with sig=9
|
||||||
|
[ERR] 2021/12/20-09:54:18 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-09:54:19 SSL_accept()
|
||||||
|
[ERR] 2021/12/20-09:54:33 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-09:54:39 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-09:55:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-09:55:30 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-10:00:07 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-10:00:14 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-10:00:17 Child killed with sig=2
|
||||||
|
[WARN] 2021/12/20-11:30:15 Could not set the CA file location
|
||||||
|
[WARN] 2021/12/20-11:30:15 Child killed with sig=9
|
||||||
|
[ERR] 2021/12/20-11:31:48 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-11:31:48 SSL_accept()
|
||||||
|
[ERR] 2021/12/20-11:32:38 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-11:32:38 SSL_accept()
|
||||||
|
[WARN] 2021/12/20-11:33:54 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-11:33:57 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-11:33:57 SSL_accept()
|
||||||
|
[WARN] 2021/12/20-11:37:21 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-11:37:24 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-11:37:40 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-11:37:42 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-11:38:03 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-11:38:03 SSL_accept()
|
||||||
|
[WARN] 2021/12/20-11:38:14 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-14:44:30 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-14:44:30 SSL_accept()
|
||||||
|
[WARN] 2021/12/20-14:44:30 Child killed with sig=9
|
||||||
|
[ERR] 2021/12/20-14:44:38 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-14:44:38 SSL_accept()
|
||||||
|
[WARN] 2021/12/20-14:44:38 Child killed with sig=9
|
||||||
|
[ERR] 2021/12/20-14:44:53 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-14:45:16 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-14:46:13 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-14:46:20 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-14:47:49 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-14:47:52 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-14:50:22 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-14:50:24 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-14:50:28 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-14:52:08 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-14:52:28 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-14:53:09 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-14:53:11 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-14:53:12 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/20-14:54:40 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-14:55:40 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/20-14:55:42 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/20-14:56:01 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:21 SSL_accept()
|
||||||
|
[ERR] 2021/12/21-09:17:21 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-09:17:21 Child killed with sig=9
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:17:27 SSL_accept()
|
||||||
|
[WARN] 2021/12/21-09:17:27 Child killed with sig=9
|
||||||
|
[ERR] 2021/12/21-09:17:27 SSL_accept()
|
||||||
|
[ERR] 2021/12/21-09:17:27 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:32:32 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-09:34:25 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-09:34:28 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-09:34:48 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-09:36:00 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:36:00 SSL_accept()
|
||||||
|
[WARN] 2021/12/21-09:36:00 Child killed with sig=9
|
||||||
|
[ERR] 2021/12/21-09:44:24 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-09:55:33 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-09:55:38 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:55:38 SSL_accept()
|
||||||
|
[WARN] 2021/12/21-09:55:38 Child killed with sig=9
|
||||||
|
[ERR] 2021/12/21-09:56:50 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[ERR] 2021/12/21-09:57:36 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-09:57:39 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-09:58:13 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-09:58:36 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-09:58:45 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-09:58:47 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-10:03:33 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-10:03:40 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-12:39:08 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-12:39:16 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-12:40:52 open_socket(): UNREACHABLE CODE REACHED!
|
||||||
|
[WARN] 2021/12/21-12:41:02 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-14:52:19 Can't init CAN bus, will try later
|
||||||
|
[WARN] 2021/12/21-14:52:27 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-14:54:28 Can't init CAN bus, will try later
|
||||||
|
[WARN] 2021/12/21-14:54:50 Child killed with sig=2
|
||||||
|
[WARN] 2021/12/21-14:56:52 Child killed with sig=2
|
||||||
|
[WARN] 2021/12/21-14:57:08 Max amount of connections: disconnect fd=6
|
||||||
|
[WARN] 2021/12/21-14:57:12 Max amount of connections: disconnect fd=6
|
||||||
|
[WARN] 2021/12/21-14:57:20 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-14:57:39 SSL error 5
|
||||||
|
[WARN] 2021/12/21-14:57:40 Child killed with sig=2
|
||||||
|
[ERR] 2021/12/21-16:27:13 SSL error 5
|
||||||
|
[WARN] 2021/12/21-16:27:16 Child killed with sig=2
|
||||||
74
Socket_CAN/server.c
Normal file
74
Socket_CAN/server.c
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "can_io.h"
|
||||||
|
#include "daemon.h"
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "sslsock.h"
|
||||||
|
|
||||||
|
int can_inited = 0;
|
||||||
|
|
||||||
|
static int try2initBTAcan(){
|
||||||
|
static double t0 = 0., t1 = 0.;
|
||||||
|
can_inited = 0;
|
||||||
|
if(dtime() - t1 < 1.) return 0; // try not more then once per second
|
||||||
|
t1 = dtime();
|
||||||
|
if(!init_can_io() || !can_ok()){
|
||||||
|
if(dtime() - t0 > 30.){ // show errors not more than onse per 30s
|
||||||
|
LOGERR("Can't init CAN bus, will try later");
|
||||||
|
WARNX("Can't init CAN bus");
|
||||||
|
t0 = dtime();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
can_inited = 1;
|
||||||
|
int rxpnt; double rxtime;
|
||||||
|
can_clean_recv(&rxpnt, &rxtime);
|
||||||
|
}
|
||||||
|
return can_inited;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read next message from CAN
|
||||||
|
// @parameter pk - packet (allocated outside)
|
||||||
|
// @return pointer to pk or NULL if none/error
|
||||||
|
can_packet *readBTAcan(can_packet *pk){
|
||||||
|
if((!can_inited || !can_ok()) && !try2initBTAcan()) return NULL;
|
||||||
|
int rxpnt, idr, len;
|
||||||
|
double rxtime;
|
||||||
|
if(!can_recv_frame(&rxpnt, &rxtime, &idr, &len, pk->data)) return NULL;
|
||||||
|
if((idr & ID_MASK) == ID_DOME){
|
||||||
|
pk->ID = (uint16_t)idr;
|
||||||
|
pk->len = (uint8_t)len;
|
||||||
|
pk->magick = CANMAGICK;
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv){
|
||||||
|
char *self = argv[0];
|
||||||
|
initial_setup();
|
||||||
|
parse_args(argc, argv);
|
||||||
|
#ifdef EBUG
|
||||||
|
#endif
|
||||||
|
try2initBTAcan();
|
||||||
|
return start_daemon(self);
|
||||||
|
}
|
||||||
29
Socket_CAN/server.h
Normal file
29
Socket_CAN/server.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#ifndef SERVER_H__
|
||||||
|
#define SERVER_H__
|
||||||
|
|
||||||
|
#include "canbus.h"
|
||||||
|
|
||||||
|
can_packet *readBTAcan(can_packet *pk);
|
||||||
|
|
||||||
|
extern int can_inited;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SERVER_H__
|
||||||
BIN
Socket_CAN/soccanclient
Executable file
BIN
Socket_CAN/soccanclient
Executable file
Binary file not shown.
BIN
Socket_CAN/soccanserver
Executable file
BIN
Socket_CAN/soccanserver
Executable file
Binary file not shown.
322
Socket_CAN/sslsock.c
Normal file
322
Socket_CAN/sslsock.c
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arpa/inet.h> // inet_ntop
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <netdb.h> // addrinfo
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <resolv.h>
|
||||||
|
#include <signal.h> // pthread_kill
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "sslsock.h"
|
||||||
|
#ifdef SERVER
|
||||||
|
#include "server.h"
|
||||||
|
#else
|
||||||
|
#include "client.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
static int OpenConn(int port){
|
||||||
|
int sd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
if(sd < 0){
|
||||||
|
LOGERR("Can't open socket");
|
||||||
|
ERRX("socket()");
|
||||||
|
}
|
||||||
|
int enable = 1;
|
||||||
|
// allow reuse of descriptor
|
||||||
|
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *)&enable, sizeof(int)) < 0){
|
||||||
|
LOGERR("Can't apply SO_REUSEADDR to socket");
|
||||||
|
ERRX("setsockopt()");
|
||||||
|
}
|
||||||
|
struct sockaddr_in addr = {0};
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
if(bind(sd, (struct sockaddr*)&addr, sizeof(addr))){
|
||||||
|
LOGWARN("Can't bind port %d", port);
|
||||||
|
ERRX("bind()");
|
||||||
|
}
|
||||||
|
if(listen(sd, BACKLOG)){
|
||||||
|
LOGWARN("Can't listen()");
|
||||||
|
ERRX("listen()");
|
||||||
|
}
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return 0 if client disconnected
|
||||||
|
static int handle_connection(SSL *ssl){
|
||||||
|
char buf[1025];
|
||||||
|
int bytes = SSL_read(ssl, buf, sizeof(buf)-1);
|
||||||
|
int sd = SSL_get_fd(ssl);
|
||||||
|
if(bytes < 1){
|
||||||
|
int sslerr = SSL_get_error(ssl, bytes);
|
||||||
|
if(SSL_ERROR_WANT_READ == sslerr ||
|
||||||
|
SSL_ERROR_WANT_WRITE == sslerr) return 1; // empty call
|
||||||
|
LOGERR("SSL error %d", sslerr);
|
||||||
|
WARNX("SSL error %d", sslerr);
|
||||||
|
return 0;
|
||||||
|
}else{
|
||||||
|
buf[bytes] = '\0';
|
||||||
|
printf("Client %d msg: \"%s\"\n", sd, buf);
|
||||||
|
LOGDBG("fd=%d, message=%s", sd, buf);
|
||||||
|
snprintf(buf, 1024, "Hello, yout FD=%d", sd);
|
||||||
|
SSL_write(ssl, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CLIENT
|
||||||
|
static int SSL_nbread(SSL *ssl, char *buf, int bufsz){
|
||||||
|
struct pollfd fds = {0};
|
||||||
|
int fd = SSL_get_fd(ssl);
|
||||||
|
fds.fd = fd;
|
||||||
|
fds.events = POLLIN;
|
||||||
|
if(poll(&fds, 1, 1) < 0){ // wait no more than 1ms
|
||||||
|
LOGWARN("SSL_nbread(): poll() failed");
|
||||||
|
WARNX("poll()");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(fds.revents == POLLIN){
|
||||||
|
DBG("Got info in fd #%d", fd);
|
||||||
|
int bytes = SSL_read(ssl, buf, bufsz);
|
||||||
|
DBG("read %d bytes", bytes);
|
||||||
|
if(bytes == 0) return -1;
|
||||||
|
if(bytes < 0){
|
||||||
|
int sslerr = SSL_get_error(ssl, bytes);
|
||||||
|
if(SSL_ERROR_WANT_READ == sslerr ||
|
||||||
|
SSL_ERROR_WANT_WRITE == sslerr) return 0; // empty call
|
||||||
|
LOGERR("SSL error %d", sslerr);
|
||||||
|
WARNX("SSL error %d", sslerr);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int OpenConn(int port){
|
||||||
|
int sd;
|
||||||
|
struct hostent *host;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
if((host = gethostbyname(G.serverhost)) == NULL ){
|
||||||
|
LOGWARN("gethostbyname(%s) error", G.serverhost);
|
||||||
|
ERRX("gethostbyname()");
|
||||||
|
}
|
||||||
|
sd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
bzero(&addr, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_addr.s_addr = *(long*)(host->h_addr);
|
||||||
|
if(connect(sd, (struct sockaddr*)&addr, sizeof(addr))){
|
||||||
|
close(sd);
|
||||||
|
LOGWARN("Can't connect to %s", G.serverhost);
|
||||||
|
ERRX("connect()");
|
||||||
|
}
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clientproc(SSL_CTX *ctx, int fd){
|
||||||
|
FNAME();
|
||||||
|
SSL *ssl;
|
||||||
|
char buf[1024];
|
||||||
|
char acClientRequest[1024] = {0};
|
||||||
|
int bytes;
|
||||||
|
ssl = SSL_new(ctx);
|
||||||
|
SSL_set_fd(ssl, fd);
|
||||||
|
if(-1 == SSL_connect(ssl)){
|
||||||
|
LOGERR("SSL_connect()");
|
||||||
|
ERRX("SSL_connect() error");
|
||||||
|
}
|
||||||
|
int enable = 1;
|
||||||
|
if(ioctl(fd, FIONBIO, (void *)&enable) < 0){
|
||||||
|
LOGERR("Can't make socket nonblocking");
|
||||||
|
ERRX("ioctl()");
|
||||||
|
}
|
||||||
|
double t0 = dtime();
|
||||||
|
int N = 0;
|
||||||
|
while(1){
|
||||||
|
if(dtime() - t0 > 3.){
|
||||||
|
DBG("Sent test message");
|
||||||
|
sprintf(acClientRequest, "Test connection #%d", ++N);
|
||||||
|
SSL_write(ssl, acClientRequest, strlen(acClientRequest));
|
||||||
|
t0 = dtime();
|
||||||
|
}
|
||||||
|
bytes = SSL_nbread(ssl, buf, sizeof(buf));
|
||||||
|
if(bytes > 0){
|
||||||
|
if(bytes == sizeof(can_packet) && ((can_packet*)buf)->magick == CANMAGICK){ // can packet
|
||||||
|
can_packet *pk = (can_packet*)buf;
|
||||||
|
#ifdef EBUG
|
||||||
|
green("Got CAN message for ID 0x%X: ", pk->ID);
|
||||||
|
for(int i = 0; i < pk->len; ++i)
|
||||||
|
printf("0x%X ", pk->data[i]);
|
||||||
|
#endif
|
||||||
|
}else{ // text message
|
||||||
|
buf[bytes] = 0;
|
||||||
|
printf("Received: \"%s\"\n", buf);
|
||||||
|
}
|
||||||
|
}else if(bytes < 0){
|
||||||
|
LOGWARN("Server disconnected or other error");
|
||||||
|
ERRX("Disconnected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SSL_free(ssl);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SSL_CTX* InitCTX(void){
|
||||||
|
const SSL_METHOD *method;
|
||||||
|
SSL_CTX *ctx;
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
method =
|
||||||
|
#ifdef CLIENT
|
||||||
|
TLS_client_method();
|
||||||
|
#else
|
||||||
|
TLS_server_method();
|
||||||
|
#endif
|
||||||
|
ctx = SSL_CTX_new(method);
|
||||||
|
if(!ctx){
|
||||||
|
LOGWARN("Can't create SSL context");
|
||||||
|
ERRX("SSL_CTX_new()");
|
||||||
|
}
|
||||||
|
if(SSL_CTX_load_verify_locations(ctx, G.ca, NULL) != 1){
|
||||||
|
LOGWARN("Could not set the CA file location\n");
|
||||||
|
ERRX("Could not set the CA file location\n");
|
||||||
|
}
|
||||||
|
#ifdef SERVER
|
||||||
|
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(G.ca));
|
||||||
|
#endif
|
||||||
|
if(SSL_CTX_use_certificate_file(ctx, G.cert, SSL_FILETYPE_PEM) <= 0){
|
||||||
|
LOGWARN("Can't use SSL certificate %s", G.cert);
|
||||||
|
ERRX("Can't use SSL certificate %s", G.cert);
|
||||||
|
}
|
||||||
|
if(SSL_CTX_use_PrivateKey_file(ctx, G.key, SSL_FILETYPE_PEM) <= 0){
|
||||||
|
LOGWARN("Can't use SSL key %s", G.key);
|
||||||
|
ERRX("Can't use SSL key %s", G.key);
|
||||||
|
}
|
||||||
|
if(!SSL_CTX_check_private_key(ctx)){
|
||||||
|
LOGWARN("Private key does not match the public certificate\n");
|
||||||
|
ERRX("Private key does not match the public certificate\n");
|
||||||
|
}
|
||||||
|
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||||
|
#ifdef SERVER
|
||||||
|
SSL_CTX_set_verify(ctx, // Specify that we need to verify the client as well
|
||||||
|
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||||
|
NULL);
|
||||||
|
#else
|
||||||
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||||
|
#endif
|
||||||
|
SSL_CTX_set_verify_depth(ctx, 1); // We accept only certificates signed only by the CA himself
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_socket(){
|
||||||
|
int fd;
|
||||||
|
SSL_library_init();
|
||||||
|
SSL_CTX *ctx = InitCTX();
|
||||||
|
fd = OpenConn(atoi(G.port));
|
||||||
|
#ifdef SERVER
|
||||||
|
int enable = 1;
|
||||||
|
if(ioctl(fd, FIONBIO, (void *)&enable) < 0){
|
||||||
|
LOGERR("Can't make socket nonblocking");
|
||||||
|
ERRX("ioctl()");
|
||||||
|
}
|
||||||
|
int nfd = 1; // only one socket @start
|
||||||
|
struct pollfd poll_set[BACKLOG+1];
|
||||||
|
memset(poll_set, 0, sizeof(poll_set));
|
||||||
|
poll_set[0].fd = fd;
|
||||||
|
poll_set[0].events = POLLIN;
|
||||||
|
SSL *ssls[BACKLOG] = {0};
|
||||||
|
double t0 = dtime();
|
||||||
|
char buf[64]; int P = 0;
|
||||||
|
while(1){
|
||||||
|
// check CAN bus and send data to all connected
|
||||||
|
can_packet canpack;
|
||||||
|
if(readBTAcan(&canpack)){
|
||||||
|
DBG("GOT CAN packet");
|
||||||
|
for(int i = nfd-1; i > -1; --i)
|
||||||
|
SSL_write(ssls[i], &canpack, sizeof(canpack));
|
||||||
|
}
|
||||||
|
if(dtime() - t0 > 5. && nfd > 1){
|
||||||
|
DBG("send ping");
|
||||||
|
snprintf(buf, 63, "ping #%d", ++P);
|
||||||
|
for(int i = nfd-2; i > -1; --i)
|
||||||
|
SSL_write(ssls[i], buf, strlen(buf));
|
||||||
|
t0 = dtime();
|
||||||
|
}
|
||||||
|
poll(poll_set, nfd, 1); // max timeout - 1ms
|
||||||
|
// check main for accept()
|
||||||
|
if(poll_set[0].revents & POLLIN){
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t len = sizeof(addr);
|
||||||
|
int client = accept(fd, (struct sockaddr*)&addr, &len);
|
||||||
|
DBG("Connection: %s: %d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
||||||
|
LOGMSG("Client %s connected to port %d (fd=%d)", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), client);
|
||||||
|
if(nfd == BACKLOG + 1){
|
||||||
|
LOGWARN("Max amount of connections: disconnect fd=%d", client);
|
||||||
|
WARNX("Limit of connections reached");
|
||||||
|
close(client);
|
||||||
|
}else{
|
||||||
|
SSL *ssl = SSL_new(ctx);
|
||||||
|
SSL_set_fd(ssl, client);
|
||||||
|
if(-1 == SSL_accept(ssl)){
|
||||||
|
LOGERR("SSL_accept()");
|
||||||
|
WARNX("SSL_accept()");
|
||||||
|
SSL_free(ssl);
|
||||||
|
}else{
|
||||||
|
ssls[nfd-1] = ssl;
|
||||||
|
memset(&poll_set[nfd], 0, sizeof(struct pollfd));
|
||||||
|
poll_set[nfd].fd = client;
|
||||||
|
poll_set[nfd].events = POLLIN;
|
||||||
|
++nfd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// scan connections
|
||||||
|
for(int fdidx = 1; fdidx < nfd; ++fdidx){
|
||||||
|
if((poll_set[fdidx].revents & POLLIN) == 0) continue;
|
||||||
|
int fd = poll_set[fdidx].fd;
|
||||||
|
if(!handle_connection(ssls[fdidx-1])){ // socket closed
|
||||||
|
SSL_free(ssls[fdidx-1]);
|
||||||
|
DBG("Client fd=%d disconnected", fd);
|
||||||
|
LOGMSG("Client fd=%d disconnected", fd);
|
||||||
|
close(fd);
|
||||||
|
// move last FD to current position
|
||||||
|
poll_set[fdidx] = poll_set[nfd - 1];
|
||||||
|
ssls[fdidx - 1] = ssls[nfd - 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
clientproc(ctx, fd);
|
||||||
|
#endif
|
||||||
|
close(fd);
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
35
Socket_CAN/sslsock.h
Normal file
35
Socket_CAN/sslsock.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SocketCAN project.
|
||||||
|
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef SSLSOCK_H__
|
||||||
|
#define SSLSOCK_H__
|
||||||
|
|
||||||
|
#if ! defined CLIENT && ! defined SERVER
|
||||||
|
#error "Define CLIENT or SERVER before including this file"
|
||||||
|
#endif
|
||||||
|
#if defined CLIENT && defined SERVER
|
||||||
|
#error "Both CLIENT and SERVER defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BACKLOG 10
|
||||||
|
|
||||||
|
int open_socket();
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SSLSOCK_H__
|
||||||
45
serialsock/Makefile
Normal file
45
serialsock/Makefile
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# run `make DEF=...` to add extra defines
|
||||||
|
PROGRAM := serialsock
|
||||||
|
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||||
|
LDFLAGS += -lusefull_macros
|
||||||
|
SRCS := $(wildcard *.c)
|
||||||
|
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
|
||||||
|
OBJDIR := mk
|
||||||
|
CFLAGS += -O3 -Wno-trampolines -std=gnu99
|
||||||
|
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o))
|
||||||
|
DEPS := $(OBJS:.o=.d)
|
||||||
|
CC = gcc
|
||||||
|
#CXX = g++
|
||||||
|
|
||||||
|
|
||||||
|
all : $(PROGRAM)
|
||||||
|
|
||||||
|
debug: CFLAGS += -DEBUG -Werror -Wall -Wextra
|
||||||
|
debug: all
|
||||||
|
|
||||||
|
$(OBJS): $(OBJDIR)
|
||||||
|
|
||||||
|
$(PROGRAM) : $(OBJS)
|
||||||
|
@echo -e "\t\tLD $(PROGRAM)"
|
||||||
|
$(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM)
|
||||||
|
|
||||||
|
$(OBJDIR):
|
||||||
|
mkdir $(OBJDIR)
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: %.c
|
||||||
|
@echo -e "\t\tCC $<"
|
||||||
|
$(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo -e "\t\tCLEAN"
|
||||||
|
@rm -f $(OBJS) $(DEPS)
|
||||||
|
@rmdir $(OBJDIR) 2>/dev/null || true
|
||||||
|
|
||||||
|
xclean: clean
|
||||||
|
@rm -f $(PROGRAM)
|
||||||
|
|
||||||
|
.PHONY: clean xclean
|
||||||
1
serialsock/Readme
Normal file
1
serialsock/Readme
Normal file
@ -0,0 +1 @@
|
|||||||
|
Socket server for my USB-CAN
|
||||||
1
serialsock/canserver.cflags
Normal file
1
serialsock/canserver.cflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c17
|
||||||
6
serialsock/canserver.config
Normal file
6
serialsock/canserver.config
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Add predefined macros for your project here. For example:
|
||||||
|
// #define THE_ANSWER 42
|
||||||
|
#define EBUG
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#define _XOPEN_SOURCE=1111
|
||||||
|
|
||||||
1
serialsock/canserver.creator
Normal file
1
serialsock/canserver.creator
Normal file
@ -0,0 +1 @@
|
|||||||
|
[General]
|
||||||
1
serialsock/canserver.cxxflags
Normal file
1
serialsock/canserver.cxxflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c++17
|
||||||
5
serialsock/canserver.files
Normal file
5
serialsock/canserver.files
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
cmdlnopts.c
|
||||||
|
cmdlnopts.h
|
||||||
|
main.c
|
||||||
|
sersock.c
|
||||||
|
sersock.h
|
||||||
1
serialsock/canserver.includes
Normal file
1
serialsock/canserver.includes
Normal file
@ -0,0 +1 @@
|
|||||||
|
.
|
||||||
95
serialsock/cmdlnopts.c
Normal file
95
serialsock/cmdlnopts.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "usefull_macros.h"
|
||||||
|
|
||||||
|
// default PID filename:
|
||||||
|
#define DEFAULT_PIDFILE "/tmp/usbsock.pid"
|
||||||
|
#define DEFAULT_PORT "1234"
|
||||||
|
#define DEFAULT_SOCKPATH "\0canbus"
|
||||||
|
|
||||||
|
static int help;
|
||||||
|
static glob_pars G = {
|
||||||
|
.pidfile = DEFAULT_PIDFILE,
|
||||||
|
.speed = 9600,
|
||||||
|
.port = DEFAULT_PORT,
|
||||||
|
.path = DEFAULT_SOCKPATH,
|
||||||
|
.logfile = NULL // don't save logs
|
||||||
|
};
|
||||||
|
glob_pars *GP = &G;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define command line options by filling structure:
|
||||||
|
* name has_arg flag val type argptr help
|
||||||
|
*/
|
||||||
|
static myoption cmdlnopts[] = {
|
||||||
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")},
|
||||||
|
{"devpath", NEED_ARG, NULL, 'd', arg_string, APTR(&G.devpath), _("serial device path")},
|
||||||
|
{"speed", NEED_ARG, NULL, 's', arg_int, APTR(&G.speed), _("serial device speed (default: 9600)")},
|
||||||
|
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), _("file to save logs (default: none)")},
|
||||||
|
{"pidfile", NEED_ARG, NULL, 'p', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")},
|
||||||
|
{"client", NO_ARGS, NULL, 'c', arg_int, APTR(&G.client), _("run as client")},
|
||||||
|
{"sockpath",NEED_ARG, NULL, 'f', arg_string, APTR(&G.path), _("socket path (start from \\0 for no files)")},
|
||||||
|
{"port", NEED_ARG, NULL, 'P', arg_string, APTR(&G.port), _("port to connect (default: " DEFAULT_PORT ")")},
|
||||||
|
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), _("increase log verbose level (default: LOG_WARN) and messages (default: none)")},
|
||||||
|
end_option
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse command line options and return dynamically allocated structure
|
||||||
|
* to global parameters
|
||||||
|
* @param argc - copy of argc from main
|
||||||
|
* @param argv - copy of argv from main
|
||||||
|
* @return allocated structure with global parameters
|
||||||
|
*/
|
||||||
|
void parse_args(int argc, char **argv){
|
||||||
|
int i;
|
||||||
|
size_t hlen = 1024;
|
||||||
|
char helpstring[1024], *hptr = helpstring;
|
||||||
|
snprintf(hptr, hlen, "Usage: %%s [args]\n\n\tWhere args are:\n");
|
||||||
|
// format of help: "Usage: progname [args]\n"
|
||||||
|
change_helpstring(helpstring);
|
||||||
|
// parse arguments
|
||||||
|
parseargs(&argc, &argv, cmdlnopts);
|
||||||
|
for(i = 0; i < argc; i++)
|
||||||
|
printf("Ignore parameter\t%s\n", argv[i]);
|
||||||
|
if(help) showhelp(-1, cmdlnopts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief verbose - print additional messages depending of G.verbose (add '\n' at end)
|
||||||
|
* @param levl - message level
|
||||||
|
* @param fmt - message
|
||||||
|
*/
|
||||||
|
void verbose(int levl, const char *fmt, ...){
|
||||||
|
va_list ar;
|
||||||
|
if(levl > G.verbose) return;
|
||||||
|
//printf("%s: ", __progname);
|
||||||
|
va_start(ar, fmt);
|
||||||
|
vprintf(fmt, ar);
|
||||||
|
va_end(ar);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
42
serialsock/cmdlnopts.h
Normal file
42
serialsock/cmdlnopts.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef CMDLNOPTS_H__
|
||||||
|
#define CMDLNOPTS_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* here are some typedef's for global data
|
||||||
|
*/
|
||||||
|
typedef struct{
|
||||||
|
char *devpath; // path to serial device
|
||||||
|
char *pidfile; // name of PID file
|
||||||
|
char *logfile; // logging to this file
|
||||||
|
char *port; // network port
|
||||||
|
char *path; // path to socket file
|
||||||
|
int speed; // connection speed
|
||||||
|
int verbose; // verbose level: for messages & logging
|
||||||
|
int client; // ==1 if application runs in client mode
|
||||||
|
} glob_pars;
|
||||||
|
|
||||||
|
extern glob_pars *GP;
|
||||||
|
|
||||||
|
void parse_args(int argc, char **argv);
|
||||||
|
void verbose(int levl, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif // CMDLNOPTS_H__
|
||||||
115
serialsock/main.c
Normal file
115
serialsock/main.c
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "sersock.h"
|
||||||
|
|
||||||
|
static TTY_descr *dev = NULL;
|
||||||
|
static pid_t childpid = 0;
|
||||||
|
int server = 1;
|
||||||
|
|
||||||
|
void signals(int sig){
|
||||||
|
if(childpid){ // slave process
|
||||||
|
DBG("Child killed with sig=%d", sig);
|
||||||
|
LOGWARN("Child killed with sig=%d", sig);
|
||||||
|
exit(sig);
|
||||||
|
}
|
||||||
|
// master process
|
||||||
|
DBG("Master process");
|
||||||
|
if(!server) restore_console();
|
||||||
|
else if(dev) close_tty(&dev);
|
||||||
|
if(sig){
|
||||||
|
DBG("Exit with signal %d", sig);
|
||||||
|
signal(sig, SIG_IGN);
|
||||||
|
LOGERR("Exit with signal %d", sig);
|
||||||
|
}else LOGERR("Exit");
|
||||||
|
if(GP->pidfile && server){
|
||||||
|
DBG("Unlink pid file");
|
||||||
|
unlink(GP->pidfile);
|
||||||
|
}
|
||||||
|
exit(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv){
|
||||||
|
char *self = strdup(argv[0]);
|
||||||
|
initial_setup();
|
||||||
|
parse_args(argc, argv);
|
||||||
|
if(GP->logfile){
|
||||||
|
int lvl = LOGLEVEL_WARN + GP->verbose;
|
||||||
|
DBG("level = %d", lvl);
|
||||||
|
if(lvl > LOGLEVEL_ANY) lvl = LOGLEVEL_ANY;
|
||||||
|
verbose(1, "Log file %s @ level %d\n", GP->logfile, lvl);
|
||||||
|
OPENLOG(GP->logfile, lvl, 1);
|
||||||
|
if(!globlog) WARNX("Can't create log file");
|
||||||
|
}
|
||||||
|
if(GP->client) server = 0;
|
||||||
|
else if(!GP->devpath){
|
||||||
|
LOGERR("You should point serial device path");
|
||||||
|
ERRX("You should point serial device path");
|
||||||
|
}
|
||||||
|
int port = atoi(GP->port);
|
||||||
|
if(port < 1024 || port > 65535){
|
||||||
|
LOGERR("Wrong port value: %d", port);
|
||||||
|
WARNX("Wrong port value: %d", port);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(server) check4running(self, GP->pidfile);
|
||||||
|
// signal reactions:
|
||||||
|
signal(SIGTERM, signals); // kill (-15) - quit
|
||||||
|
signal(SIGHUP, SIG_IGN); // hup - ignore
|
||||||
|
signal(SIGINT, signals); // ctrl+C - quit
|
||||||
|
signal(SIGQUIT, signals); // ctrl+\ - quit
|
||||||
|
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z
|
||||||
|
LOGMSG("Started");
|
||||||
|
#ifndef EBUG
|
||||||
|
if(server){
|
||||||
|
unsigned int pause = 5;
|
||||||
|
while(1){
|
||||||
|
childpid = fork();
|
||||||
|
if(childpid){ // master
|
||||||
|
double t0 = dtime();
|
||||||
|
LOGMSG("Created child with pid %d", childpid);
|
||||||
|
wait(NULL);
|
||||||
|
LOGWARN("Child %d died", childpid);
|
||||||
|
if(dtime() - t0 < 1.) pause += 5;
|
||||||
|
else pause = 1;
|
||||||
|
if(pause > 900) pause = 900;
|
||||||
|
sleep(pause); // wait a little before respawn
|
||||||
|
}else{ // slave
|
||||||
|
prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return start_socket(server, GP->path, &dev);
|
||||||
|
}
|
||||||
386
serialsock/sersock.c
Normal file
386
serialsock/sersock.c
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h> // unix socket
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "sersock.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wait for answer from socket
|
||||||
|
* @param sock - socket fd
|
||||||
|
* @return 0 in case of error or timeout, 1 in case of socket ready
|
||||||
|
*/
|
||||||
|
static int waittoread(int sock){
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval timeout;
|
||||||
|
int rc;
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 100;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(sock, &fds);
|
||||||
|
do{
|
||||||
|
rc = select(sock+1, &fds, NULL, NULL, &timeout);
|
||||||
|
if(rc < 0){
|
||||||
|
if(errno != EINTR){
|
||||||
|
WARN("select()");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}while(1);
|
||||||
|
if(FD_ISSET(sock, &fds)){
|
||||||
|
//DBG("FD_ISSET");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// work with single client, return FALSE if disconnected
|
||||||
|
static int handle_socket(int sock, TTY_descr *d){
|
||||||
|
char buff[BUFLEN];
|
||||||
|
ssize_t rd = read(sock, buff, BUFLEN-1);;
|
||||||
|
DBG("Got %zd bytes", rd);
|
||||||
|
if(rd <= 0){ // error or disconnect
|
||||||
|
DBG("Nothing to read from fd %d (ret: %zd)", sock, rd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
// add trailing zero to be on the safe side
|
||||||
|
buff[rd] = 0;
|
||||||
|
DBG("GOT: %s", buff);
|
||||||
|
ssize_t blen = strlen(buff);
|
||||||
|
if(blen != write(d->comfd, buff, blen)){
|
||||||
|
LOGWARN("write()");
|
||||||
|
WARN("write()");
|
||||||
|
}
|
||||||
|
if(buff[blen-1] == '\n') buff[blen-1] = 0;
|
||||||
|
LOGMSG("CLIENT_%d: %s", sock, buff);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check data from fd
|
||||||
|
* @param fd - file descriptor
|
||||||
|
* @return 0 in case of timeout, 1 in case of fd have data, -1 if error
|
||||||
|
*/
|
||||||
|
static int canberead(int fd){
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 100;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
do{
|
||||||
|
int rc = select(fd+1, &fds, NULL, NULL, &timeout);
|
||||||
|
if(rc < 0){
|
||||||
|
if(errno != EINTR){
|
||||||
|
LOGWARN("select()");
|
||||||
|
WARN("select()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}while(1);
|
||||||
|
if(FD_ISSET(fd, &fds)){
|
||||||
|
DBG("FD_ISSET");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getserdata - read data (ending by '\n') from serial device
|
||||||
|
* @param D (i) - device
|
||||||
|
* @param len (o) - amount of butes read (-1 if disconnected)
|
||||||
|
* @return pointer to data buffer or NULL if none
|
||||||
|
*/
|
||||||
|
static char *getserdata(TTY_descr *D, int *len){
|
||||||
|
static char serbuf[BUFLEN], *ptr = serbuf;
|
||||||
|
static size_t blen = BUFLEN - 1;
|
||||||
|
if(!D || D->comfd < 0) return NULL;
|
||||||
|
char *nl = NULL;
|
||||||
|
do{
|
||||||
|
int s = canberead(D->comfd);
|
||||||
|
if(s == 0) break;
|
||||||
|
if(s < 0){ // interrupted?
|
||||||
|
if(len) *len = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ssize_t l = read(D->comfd, ptr, blen);
|
||||||
|
if(l < 1){ // disconnected
|
||||||
|
DBG("device disconnected");
|
||||||
|
if(len) *len = -1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ptr[l] = 0;
|
||||||
|
DBG("GOT %zd bytes: '%s'", l, ptr);
|
||||||
|
nl = strchr(ptr, '\n');
|
||||||
|
ptr += l;
|
||||||
|
blen -= l;
|
||||||
|
if(nl){
|
||||||
|
DBG("Got newline");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}while(blen);
|
||||||
|
// recalculate newline from the beginning (what if old data stays there?)
|
||||||
|
nl = strchr(serbuf, '\n');
|
||||||
|
if(blen && !nl){
|
||||||
|
if(len) *len = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// in case of overflow send buffer without trailing '\n'
|
||||||
|
int L;
|
||||||
|
if(nl) L = nl - serbuf + 1; // get line to '\n'
|
||||||
|
else L = strlen(serbuf); // get all buffer
|
||||||
|
if(len) *len = L;
|
||||||
|
memcpy(D->buf, serbuf, L); // copy all + trailing zero
|
||||||
|
D->buflen = L;
|
||||||
|
D->buf[L] = 0;
|
||||||
|
DBG("Put to buf %d bytes: '%s'", L, D->buf);
|
||||||
|
if(nl){
|
||||||
|
L = ptr - nl - 1; // symbols after newline
|
||||||
|
if(L > 0){ // there's some data after '\n' -> put it into the beginning
|
||||||
|
memmove(serbuf, nl+1, L);
|
||||||
|
blen = BUFLEN - 1 - L;
|
||||||
|
ptr = serbuf + L;
|
||||||
|
*ptr = 0;
|
||||||
|
DBG("now serbuf is '%s'", serbuf);
|
||||||
|
}else{
|
||||||
|
blen = BUFLEN - 1;
|
||||||
|
ptr = serbuf;
|
||||||
|
*ptr = 0;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
blen = BUFLEN - 1;
|
||||||
|
ptr = serbuf;
|
||||||
|
*ptr = 0;
|
||||||
|
}
|
||||||
|
return D->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_(int sock, TTY_descr *d){
|
||||||
|
if(listen(sock, MAXCLIENTS) == -1){
|
||||||
|
WARN("listen");
|
||||||
|
LOGWARN("listen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int enable = 1;
|
||||||
|
if(ioctl(sock, FIONBIO, (void *)&enable) < 0){ // make socket nonblocking
|
||||||
|
LOGERR("Can't make socket nonblocking");
|
||||||
|
ERRX("ioctl()");
|
||||||
|
}
|
||||||
|
int nfd = 1; // only one socket @start
|
||||||
|
struct pollfd poll_set[MAXCLIENTS+1];
|
||||||
|
bzero(poll_set, sizeof(poll_set));
|
||||||
|
// ZERO - listening server socket
|
||||||
|
poll_set[0].fd = sock;
|
||||||
|
poll_set[0].events = POLLIN;
|
||||||
|
while(1){
|
||||||
|
poll(poll_set, nfd, 1); // max timeout - 1ms
|
||||||
|
if(poll_set[0].revents & POLLIN){ // check main for accept()
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t len = sizeof(addr);
|
||||||
|
int client = accept(sock, (struct sockaddr*)&addr, &len);
|
||||||
|
DBG("New connection");
|
||||||
|
LOGMSG("Connection, fd=%d", client);
|
||||||
|
if(nfd == MAXCLIENTS + 1){
|
||||||
|
LOGWARN("Max amount of connections, disconnect fd=%d", client);
|
||||||
|
WARNX("Limit of connections reached");
|
||||||
|
close(client);
|
||||||
|
}else{
|
||||||
|
memset(&poll_set[nfd], 0, sizeof(struct pollfd));
|
||||||
|
poll_set[nfd].fd = client;
|
||||||
|
poll_set[nfd].events = POLLIN;
|
||||||
|
++nfd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int l = -1;
|
||||||
|
char *serdata = getserdata(d, &l);
|
||||||
|
if(l < 0){
|
||||||
|
LOGERR("Serial device disconnected");
|
||||||
|
ERRX("Serial device disconnected");
|
||||||
|
}
|
||||||
|
if(serdata){
|
||||||
|
for(int i = 1; i < nfd; ++i)
|
||||||
|
if(l != write(poll_set[i].fd, serdata, l)){
|
||||||
|
LOGWARN("write()");
|
||||||
|
WARN("write()");
|
||||||
|
}
|
||||||
|
if(serdata[l-1] == '\n') serdata[l-1] = 0;
|
||||||
|
LOGMSG("SERIAL: %s", serdata);
|
||||||
|
}
|
||||||
|
// scan connections
|
||||||
|
for(int fdidx = 1; fdidx < nfd; ++fdidx){
|
||||||
|
if((poll_set[fdidx].revents & POLLIN) == 0) continue;
|
||||||
|
int fd = poll_set[fdidx].fd;
|
||||||
|
if(!handle_socket(fd, d)){ // socket closed
|
||||||
|
DBG("Client fd=%d disconnected", fd);
|
||||||
|
LOGMSG("Client fd=%d disconnected", fd);
|
||||||
|
close(fd);
|
||||||
|
// move last FD to current position
|
||||||
|
poll_set[fdidx] = poll_set[nfd - 1];
|
||||||
|
--nfd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read console char - for client
|
||||||
|
static int rc(){
|
||||||
|
int rb;
|
||||||
|
struct timeval tv;
|
||||||
|
int retval;
|
||||||
|
fd_set rfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(STDIN_FILENO, &rfds);
|
||||||
|
tv.tv_sec = 0; tv.tv_usec = 100;
|
||||||
|
retval = select(1, &rfds, NULL, NULL, &tv);
|
||||||
|
if(!retval) rb = 0;
|
||||||
|
else {
|
||||||
|
if(FD_ISSET(STDIN_FILENO, &rfds)) rb = getchar();
|
||||||
|
else rb = 0;
|
||||||
|
}
|
||||||
|
return rb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief mygetline - silently and non-blocking getline
|
||||||
|
* @return zero-terminated string with '\n' at end (or without in case of overflow)
|
||||||
|
*/
|
||||||
|
static char *mygetline(){
|
||||||
|
static char buf[BUFLEN+1];
|
||||||
|
static int i = 0;
|
||||||
|
while(i < BUFLEN){
|
||||||
|
char rd = rc();
|
||||||
|
if(!rd) return NULL;
|
||||||
|
if(rd == 0x7f && i){ // backspace
|
||||||
|
buf[--i] = 0;
|
||||||
|
printf("\b \b");
|
||||||
|
}else{
|
||||||
|
buf[i++] = rd;
|
||||||
|
printf("%c", rd);
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
if(rd == '\n') break;
|
||||||
|
}
|
||||||
|
buf[i] = 0;
|
||||||
|
i = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_(int sock){
|
||||||
|
setup_con(); // convert console mode into non-canon
|
||||||
|
int Bufsiz = BUFLEN;
|
||||||
|
char *recvBuff = MALLOC(char, Bufsiz);
|
||||||
|
while(1){
|
||||||
|
char *msg = mygetline();
|
||||||
|
if(msg){
|
||||||
|
ssize_t L = strlen(msg);
|
||||||
|
if(send(sock, msg, L, 0) != L){
|
||||||
|
WARN("send");
|
||||||
|
WARN("send");
|
||||||
|
}
|
||||||
|
if(msg[L-1] == '\n') msg[L-1] = 0;
|
||||||
|
LOGMSG("TERMINAL: %s", msg);
|
||||||
|
}
|
||||||
|
if(!waittoread(sock)) continue;
|
||||||
|
int n = read(sock, recvBuff, Bufsiz-1);
|
||||||
|
if(n == 0){
|
||||||
|
WARNX("Server disconnected");
|
||||||
|
signals(0);
|
||||||
|
}
|
||||||
|
recvBuff[n] = 0;
|
||||||
|
printf("%s", recvBuff);
|
||||||
|
if(recvBuff[n-1] == '\n') recvBuff[n-1] = 0;
|
||||||
|
LOGMSG("SERIAL: %s", recvBuff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief openserialdev - open connection to serial device
|
||||||
|
* @param path (i) - path to device
|
||||||
|
* @param speed - connection speed
|
||||||
|
* @return pointer to device structure if all OK
|
||||||
|
*/
|
||||||
|
static TTY_descr *openserialdev(char *path, int speed){
|
||||||
|
TTY_descr *d = new_tty(path, speed, BUFLEN);
|
||||||
|
DBG("Device created");
|
||||||
|
if(!d || !(tty_open(d, 1))){
|
||||||
|
WARN("Can't open device %s", path);
|
||||||
|
LOGWARN("Can't open device %s", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
DBG("device opened");
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int start_socket(int server, char *path, TTY_descr **dev){
|
||||||
|
if(server){
|
||||||
|
if(!dev) return 1;
|
||||||
|
if(!(*dev = openserialdev(GP->devpath, GP->speed))){
|
||||||
|
LOGERR("Can't open serial device %s", GP->devpath);
|
||||||
|
ERR("Can't open serial device %s", GP->devpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int sock = -1;
|
||||||
|
int reuseaddr = 1;
|
||||||
|
struct sockaddr_un saddr = {0};
|
||||||
|
saddr.sun_family = AF_UNIX;
|
||||||
|
strncpy(saddr.sun_path, path, 106); // if sun_path[0] == 0 we don't create a file
|
||||||
|
if((sock = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0){ // or SOCK_STREAM?
|
||||||
|
LOGERR("socket()");
|
||||||
|
ERR("socket()");
|
||||||
|
}
|
||||||
|
if(server){
|
||||||
|
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){
|
||||||
|
LOGWARN("setsockopt");
|
||||||
|
WARN("setsockopt");
|
||||||
|
}
|
||||||
|
if(bind(sock, &saddr, sizeof(saddr)) == -1){
|
||||||
|
close(sock);
|
||||||
|
LOGERR("bind");
|
||||||
|
ERR("bind");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(connect(sock, &saddr, sizeof(saddr)) == -1){
|
||||||
|
LOGERR("connect()");
|
||||||
|
ERR("connect()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(server) server_(sock, *dev);
|
||||||
|
else client_(sock);
|
||||||
|
close(sock);
|
||||||
|
signals(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
31
serialsock/sersock.h
Normal file
31
serialsock/sersock.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2022 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef SERSOCK_H__
|
||||||
|
#define SERSOCK_H__
|
||||||
|
|
||||||
|
#define BUFLEN (1024)
|
||||||
|
// Max amount of connections
|
||||||
|
#define MAXCLIENTS (30)
|
||||||
|
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
int start_socket(int server, char *path, TTY_descr **dev);
|
||||||
|
|
||||||
|
#endif // SERSOCK_H__
|
||||||
Loading…
x
Reference in New Issue
Block a user