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
|
||||
|
||||
serialsock - socket server for serial devices
|
||||
|
||||
simple_list - 1-directional list with functions: add element; delete list
|
||||
|
||||
stellarium_emul - snippet for stellarium telescope remote control
|
||||
@ -23,3 +25,7 @@ usefull_macros - a lot of different macros & functions
|
||||
* MMAP files into memory
|
||||
|
||||
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-----
|
||||
MIIFGDCCAwACFB0zmHjuRItxermFXMnfu8ZsBv+NMA0GCSqGSIb3DQEBCwUAMFAx
|
||||
CzAJBgNVBAYTAlJVMQ0wCwYDVQQIDARLQ2hSMQ8wDQYDVQQHDAZCdWtvdm8xEDAO
|
||||
BgNVBAoMB1NBTyBSQVMxDzANBgNVBAMMBnNhby5ydTAgFw0yMTEyMjAwODE3NDBa
|
||||
GA8yMTIxMTIyMDA4MTc0MFowPzELMAkGA1UEBhMCUlUxDTALBgNVBAgMBEtDaFIx
|
||||
DzANBgNVBAcMBkJ1a292bzEQMA4GA1UECgwHU0FPIFJBUzCCAiIwDQYJKoZIhvcN
|
||||
AQEBBQADggIPADCCAgoCggIBALwxkEemASoXwJu8qEIFhnOqrn50Gj6xI8O4/2Ry
|
||||
yB35nisR3VB24a5cdBvXzCq7PfuVzCtHCnKbLxPJhA5HJAB4MHOyXH97NKp0Ihpp
|
||||
/8A3FWJq/oNF0QpnBlSKVlQ/5Omh7kWzzqNlQHIIJpgyZZJlePi1RBjCK0h+HZMg
|
||||
+/1jutvtFRGXOcbRLke8Vm5NSmdPBAYLCzaoByCCqefhxmdiSnUC6TgPqiGgSxQ7
|
||||
SSMB/sdbADd9e8pEZRGWMyU2z6X8GtuyRkIKC4txdPYdAxBNSe32nHDOx4RE0Gsj
|
||||
SzqCQ2di+mzh4mbeQGJLQprqNRLbR1moppumBM9qatL9bDr+NIOJVj9y2RqmEbuX
|
||||
LzV8f0vMv61k89ZlQJro5y+4AffwpKXDrHqXaALhUvD80xZDvTRRZrBTC5cLvCC/
|
||||
Qx5Lq8hI/Yp/N8E4ZLIJGL0PJ0gKiuUQabLGNydqLxLuDp4nwPvRQdsB/MVErlw1
|
||||
ojA9L0wNWvxTJl5tCflcIH9imCceuIhGP9+TGuJdknZPk1pl97wfQjWGunbkHWzw
|
||||
20bQXL1fsqZOYHIaRjX/TRsIo8A6xOo9tM+J8tlkr6Vbf177xv+yxblMOhMnbi77
|
||||
efSKDImjmqrAm7EzxzOximrAxRjJEANtgfoFCY205cwM8uepnJYoTg4ZY4YLuHX9
|
||||
lInvAgMBAAEwDQYJKoZIhvcNAQELBQADggIBALG6oAI97WWjGKVkfZZMDCztpkJw
|
||||
GQOPArtPqz+rmVPC2YsqAK891TbiJ+vfniQ4u17+oJp+UeeTfBkRsLyHpdIWjqpZ
|
||||
OG5Q3+fIMvlWKv1Vds76gY6fbnGPdI3rFZASl4qhN85K3a8T7AsB4pkBjJg0W/sO
|
||||
sgDU3s+8XUsuSQtIhgXS4Rl2upEjrJ1/9/3HOwcsHX7Qe2VgInN8r2vLXz0Tn86A
|
||||
yB0ZqmhqjTaA6aObd3ncx2m4UD9IU2h1IoDRpmJP9Rfeyovdp1IGS5FQEsrJkxXS
|
||||
gYCgzsWq1X6u3NF9Rtu4b8tY7BGK11lvds2J8QCJZomW6A+WSNK20ksR044SlSy6
|
||||
RvNioaDIkL0mKhMu87DJnB2phDTmF/6SFVQtNt9MWtOuAUujrn9FiNVeBxqnkzP7
|
||||
Fq4zMgmZVjKydA5BiR1cXCH/0C+jOPmaGUSvxVLX9B3U81Tj2jBBLh5C4QHy/D8f
|
||||
DPFN5WOrpbrfH9HOstC0Kk4bLHq4xsFtwEz7N/8aL9ahutejVlaKaviaBA3sJ+uv
|
||||
oz0cEa8Bn4owDDnGwRPeimxNHd+C8dulUoZQ/ukT8ah6cuo35ykYdOiOgqewTsPT
|
||||
2J3hJa1DqD9zkH2BzLatHEdZkXpNtgF8RRpDH3m1ZsS4a4ykd03oYEoh3XOFVbwi
|
||||
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-----
|
||||
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
|
||||
-----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-----
|
||||
MIIFGDCCAwACFB0zmHjuRItxermFXMnfu8ZsBv+MMA0GCSqGSIb3DQEBCwUAMFAx
|
||||
CzAJBgNVBAYTAlJVMQ0wCwYDVQQIDARLQ2hSMQ8wDQYDVQQHDAZCdWtvdm8xEDAO
|
||||
BgNVBAoMB1NBTyBSQVMxDzANBgNVBAMMBnNhby5ydTAgFw0yMTEyMjAwODE3NDBa
|
||||
GA8yMTIxMTIyMDA4MTc0MFowPzELMAkGA1UEBhMCUlUxDTALBgNVBAgMBEtDaFIx
|
||||
DzANBgNVBAcMBkJ1a292bzEQMA4GA1UECgwHU0FPIFJBUzCCAiIwDQYJKoZIhvcN
|
||||
AQEBBQADggIPADCCAgoCggIBAM/Iqcldh+6UfwTJySrY7WpzFlUTq2c0nwTyvRDD
|
||||
P1+R9RytzyOwnkKMRvU4Bs40iftpacwlU4JfQGGeQn1g7507rRlalIxt11D2kB+h
|
||||
Hh7V8pS13Y5Y1yOTZlhExdKrs1A3EpaEl4wurF2Rxk6fQMfGoi18Tx/jvjy5diT2
|
||||
LTWv+KObxFIJv7o0ikLdvdLFdqobWn4xaYNjP6M7+3IlWCU8N0ickAprKBHOf9jF
|
||||
gE3ABjNuMYUY1gX9dJbkEbhjrvIcbjC5MmknMoR1HHbG8MHLgEbcbu0ZFgj7pu01
|
||||
QfiByEbLgDT1xl4pZ8S+6d4q7lPmkwmJzwGJr5ZmCqyT7A4i01AqVRHbezZvR0oV
|
||||
4QusErhKxvGh7123H/OrSvfwIxEIbWEAIzvWaxV14ctLKOiOw+mENltQxFWziaiG
|
||||
NHXM38SHQNSmTHJUWC08IUqslR5r1Ys4h15vdJ+ZMVpw1ijNIW0C9zgdJu/ERkaC
|
||||
nVSW5rl3gicou4NobomKscHfnyYTiPUWZ+GccnNR35xlSbGSmjzPwYtvvX0UOn8w
|
||||
Sp2oCeW6PQuWJDpVOlTFgQwJNVT6T9J2XW/wtlNWyZGjM3tATqAlpXTrrapJzTlL
|
||||
uEGpkebKIMTLnDa/DXemy1A7ehjyKMXfXC4pzwEsR12oPfZ1qyO+lQJPYV0Ur+on
|
||||
SNlZAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAJH7lEF/tpLN0uOz7pnUdTT2A3IF
|
||||
0cehqlhv2E8pXLQ7lydAwMuSh582/jCPx9f/aAz11MKfcUwdSBJvdinLvOpM0qCN
|
||||
0i2aCxHGXnC9kVRsukCkKbF2/+hqoM/Cfmi995f1eEgrk/QkR34HC/2745mh//3S
|
||||
i69jzwbEGDM7YuGisY25OYSyT37SHR56dU/j1SRw9JgfIEC4DPzS38oqWQfEJjEk
|
||||
VCg2XrPwUmRk6eLqC80pBL4tmItT1RTERN/0vBNVivHZrseEGWrtMsq52mDEPuVf
|
||||
mijF6ImVkonKi7ouIrTE/4no3TpNjjUTlMNYumedO38q30/4A0+wjHvsP42b9e5V
|
||||
bahjejgwlhhbFaEkUpKk9ApcM6Pqq8kURoWgzcmjrUYuXryWAPKWTwE5Y939CgsV
|
||||
DJXbSkITl61jZQWyAzl5kEUPVguBwJjOyL2zsxbLcHuvIx51RDEa0xl9sKp4kCJR
|
||||
FoLyexymVyMw8yPenPL0jF7LvY1ua6+60avE7tNnJ0DdWt0DIjEUtqmuQEfBUP0M
|
||||
n0q/fO9+ZOqfOhuNLPKlw2UFKCw2xd6SU6qm0BFebLiIBkvU4GQ3IWwNGZWw+66J
|
||||
UzDRHzWiVNED+IBrdGE43+1TdROkKz0HCiIrAnE7gjWeaq2ShGmjaabyYOFE0FoJ
|
||||
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