mirror of
https://github.com/eddyem/eddys_snippets.git
synced 2025-12-06 02:35:12 +03:00
add socket snippet
This commit is contained in:
parent
0da6bce6e9
commit
76a1ec0e81
4
Socket_CAN/socketcan0
Executable file
4
Socket_CAN/socketcan0
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
ip link set can0 type can bitrate 100000 triple-sampling on
|
||||||
|
ifconfig can0 up
|
||||||
45
Socket_snippet/Makefile
Normal file
45
Socket_snippet/Makefile
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# run `make DEF=...` to add extra defines
|
||||||
|
PROGRAM := socket
|
||||||
|
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
|
||||||
|
LDFLAGS += -lusefull_macros -lm -L/usr/local/lib/
|
||||||
|
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) $(OBJS) $(LDFLAGS) -o $(PROGRAM)
|
||||||
|
|
||||||
|
$(OBJDIR):
|
||||||
|
mkdir $(OBJDIR)
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: %.c
|
||||||
|
@echo -e "\t\tCC $<"
|
||||||
|
$(CC) $< -MD -c $(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_snippet/Readme.md
Normal file
7
Socket_snippet/Readme.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Socket server and client snippet
|
||||||
|
================================
|
||||||
|
|
||||||
|
This snippet allows to create some utilities than can be run both in client or server mode.
|
||||||
|
The sockets are **local** TCP or UNIX sockets. Server-side polling use `poll()`.
|
||||||
|
|
||||||
|
The pieces of user code may be in comments marked `USERCODE`
|
||||||
120
Socket_snippet/client.c
Normal file
120
Socket_snippet/client.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// client-side functions
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief processData - process here some actions and make messages for server
|
||||||
|
* @param buf (o) - buffer for answer
|
||||||
|
* @param l - max length of buf
|
||||||
|
* @return amount of answer bytes
|
||||||
|
*/
|
||||||
|
static int process_data(char *buf, int l){
|
||||||
|
if(!buf || !l) return 0;
|
||||||
|
/* USERCODE: get here some data to send */
|
||||||
|
static double t0 = 0.;
|
||||||
|
if(dtime() - t0 > 1.){
|
||||||
|
t0 = dtime();
|
||||||
|
// send random commands each 1 second
|
||||||
|
int x = rand() % 600;
|
||||||
|
const char *cmd = NULL;
|
||||||
|
if(x < 100) cmd = "time";
|
||||||
|
else if(x < 200) cmd = "getval1";
|
||||||
|
else if(x < 300) cmd = "getval2";
|
||||||
|
else if(x < 400) cmd = "ping";
|
||||||
|
if(cmd) snprintf(buf, l, "%s", cmd);
|
||||||
|
else{
|
||||||
|
if(x < 500) snprintf(buf, l, "setval1=%d", rand() & 0xff);
|
||||||
|
else snprintf(buf, l, "setval2=%d", rand() & 0xff);
|
||||||
|
}
|
||||||
|
return strlen(buf);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief process_server_message - parse messages from server and make an answer
|
||||||
|
* @param buf (io) - incoming message (the answer will be in this buffer)
|
||||||
|
* @param l - buff max length
|
||||||
|
* @return amount of answer bytes
|
||||||
|
*/
|
||||||
|
static int process_server_message(char *buf, int l){
|
||||||
|
/* USERCODE inside this funtion */
|
||||||
|
if(!buf || !l) return 0;
|
||||||
|
// just show on screen
|
||||||
|
green("SERVER send: %s\n", buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check data from fd (polling function for client)
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void client(int sock){
|
||||||
|
char buf[BUFLEN];
|
||||||
|
while(1){
|
||||||
|
int l = process_data(buf, BUFLEN-1);
|
||||||
|
if(l) sendmessage(sock, buf, l);
|
||||||
|
if(1 != canberead(sock)) continue;
|
||||||
|
int n = read(sock, buf, BUFLEN-1);
|
||||||
|
if(n == 0){
|
||||||
|
WARNX("Server disconnected");
|
||||||
|
signals(0);
|
||||||
|
}
|
||||||
|
buf[n] = 0;
|
||||||
|
DBG("Got from server: %s", buf);
|
||||||
|
LOGMSG("Got from server: %s", buf);
|
||||||
|
l = process_server_message(buf, n);
|
||||||
|
if(l) sendmessage(sock, buf, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Socket_snippet/client.h
Normal file
26
Socket_snippet/client.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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 CLIENT_H__
|
||||||
|
#define CLIENT_H__
|
||||||
|
|
||||||
|
// client-side functions
|
||||||
|
void client(int fd);
|
||||||
|
|
||||||
|
#endif // CLIENT_H__
|
||||||
83
Socket_snippet/cmdlnopts.c
Normal file
83
Socket_snippet/cmdlnopts.c
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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 <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "usefull_macros.h"
|
||||||
|
|
||||||
|
// default PID filename:
|
||||||
|
#define DEFAULT_PIDFILE "/tmp/usbsock.pid"
|
||||||
|
|
||||||
|
static int help;
|
||||||
|
static glob_pars G = {
|
||||||
|
.pidfile = DEFAULT_PIDFILE,
|
||||||
|
};
|
||||||
|
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")},
|
||||||
|
{"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")},
|
||||||
|
{"path", NEED_ARG, NULL, 'N', arg_string, APTR(&G.path), _("UNIX socket path/name (start from \\0 for no files)")},
|
||||||
|
{"port", NEED_ARG, NULL, 'P', arg_string, APTR(&G.port), _("port to connect (for local TCP socket)")},
|
||||||
|
{"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;
|
||||||
|
va_start(ar, fmt);
|
||||||
|
vprintf(fmt, ar);
|
||||||
|
va_end(ar);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
40
Socket_snippet/cmdlnopts.h
Normal file
40
Socket_snippet/cmdlnopts.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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 *pidfile; // name of PID file
|
||||||
|
char *logfile; // logging to this file
|
||||||
|
char *path; // path to UNIX-socket file
|
||||||
|
char *port; // local TCP socket port
|
||||||
|
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__
|
||||||
108
Socket_snippet/main.c
Normal file
108
Socket_snippet/main.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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 <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
static pid_t childpid = 0;
|
||||||
|
static int isserver = 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(sig){
|
||||||
|
DBG("Exit with signal %d", sig);
|
||||||
|
signal(sig, SIG_IGN);
|
||||||
|
LOGERR("Exit with signal %d", sig);
|
||||||
|
}else LOGERR("Exit");
|
||||||
|
if(GP->pidfile && isserver){
|
||||||
|
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) isserver = 0;
|
||||||
|
if(GP->port){
|
||||||
|
if(GP->path){
|
||||||
|
WARNX("Options `port` and `path` can't be used together! Point `port` for TCP socket or `path` for UNIX.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int port = atoi(GP->port);
|
||||||
|
if(port < PORTN_MIN || port > PORTN_MAX){
|
||||||
|
WARNX("Wrong port value: %d", port);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}else if(!GP->path) ERRX("You should point option `port` or `path`!");
|
||||||
|
|
||||||
|
if(isserver) 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(isserver){
|
||||||
|
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
|
||||||
|
if(GP->path) return start_socket(isserver, GP->path, FALSE);
|
||||||
|
if(GP->port) return start_socket(isserver, GP->port, TRUE);
|
||||||
|
}
|
||||||
150
Socket_snippet/server.c
Normal file
150
Socket_snippet/server.c
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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 <netdb.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
// server-side functions
|
||||||
|
|
||||||
|
// command handlers
|
||||||
|
hresult pinghandler(int fd, _U_ const char *key, _U_ const char *val){
|
||||||
|
sendstrmessage(fd, "PING");
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sendtime = 0;
|
||||||
|
hresult timehandler(_U_ int fd, _U_ const char *key, _U_ const char *val){
|
||||||
|
sendtime = 1;
|
||||||
|
return RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int value1 = 0, value2 = 0;
|
||||||
|
hresult valsethandler(_U_ int fd, const char *key, const char *val){
|
||||||
|
if(!val || !*val) return RESULT_BADVAL;
|
||||||
|
int i = atoi(val);
|
||||||
|
if(i < -65535 || i > 65535) return RESULT_BADVAL;
|
||||||
|
if(strcmp(key, "setval1") == 0) value1 = i;
|
||||||
|
else value2 = i;
|
||||||
|
return RESULT_OK;
|
||||||
|
}
|
||||||
|
hresult valgethandler(int fd, const char *key, _U_ const char *val){
|
||||||
|
char buf[32];
|
||||||
|
if(strcmp(key, "getval1") == 0) snprintf(buf, 32, "VAL1=%d", value1);
|
||||||
|
else snprintf(buf, 32, "VAL2=%d", value2);
|
||||||
|
sendstrmessage(fd, buf);
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
hresult handler(_U_ int fd, _U_ const char *key, _U_ const char *val){
|
||||||
|
;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static handleritem items[] = {
|
||||||
|
{pinghandler, "ping"},
|
||||||
|
{timehandler, "time"},
|
||||||
|
{valsethandler, "setval1"},
|
||||||
|
{valsethandler, "setval2"},
|
||||||
|
{valgethandler, "getval1"},
|
||||||
|
{valgethandler, "getval2"},
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief processData - process here some actions and make messages for all clients
|
||||||
|
* @param buf (o) - buffer for answer
|
||||||
|
* @param l - max length of buf
|
||||||
|
* @return amount of answer bytes
|
||||||
|
*/
|
||||||
|
static int process_data(char *buf, int l){
|
||||||
|
if(!buf || !l) return 0;
|
||||||
|
/* USERCODE: get here some data to send all clients */
|
||||||
|
if(sendtime){
|
||||||
|
snprintf(buf, l, "TIME=%.2f", dtime());
|
||||||
|
sendtime = 0;
|
||||||
|
return strlen(buf);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CLBUFSZ BUFSIZ
|
||||||
|
|
||||||
|
void server(int sock){
|
||||||
|
if(listen(sock, MAXCLIENTS) == -1){
|
||||||
|
WARN("listen");
|
||||||
|
LOGWARN("listen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int nfd = 1; // only one socket @start
|
||||||
|
struct pollfd poll_set[MAXCLIENTS+1];
|
||||||
|
char buffers[MAXCLIENTS][CLBUFSZ]; // buffers for data reading
|
||||||
|
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("SERVER got 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char buff[BUFLEN];
|
||||||
|
int l = 0;
|
||||||
|
// process some data & send messages to ALL
|
||||||
|
if((l = process_data(buff, BUFLEN-1))){
|
||||||
|
DBG("Send to %d clients", nfd - 1);
|
||||||
|
for(int i = 1; i < nfd; ++i)
|
||||||
|
sendmessage(poll_set[i].fd, buff, l);
|
||||||
|
}
|
||||||
|
// scan connections
|
||||||
|
for(int fdidx = 1; fdidx < nfd; ++fdidx){
|
||||||
|
if((poll_set[fdidx].revents & POLLIN) == 0) continue;
|
||||||
|
int fd = poll_set[fdidx].fd;
|
||||||
|
if(!processData(fd, items, buffers[fdidx-1], CLBUFSZ)){ // socket closed
|
||||||
|
DBG("Client fd=%d disconnected", fd);
|
||||||
|
LOGMSG("SERVER client fd=%d disconnected", fd);
|
||||||
|
buffers[fdidx-1][0] = 0; // clear rest of data in buffer
|
||||||
|
close(fd);
|
||||||
|
// move last FD to current position
|
||||||
|
poll_set[fdidx] = poll_set[nfd - 1];
|
||||||
|
--nfd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Socket_snippet/server.h
Normal file
26
Socket_snippet/server.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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 SERVER_H__
|
||||||
|
#define SERVER_H__
|
||||||
|
|
||||||
|
// server-side functions
|
||||||
|
void server(int fd);
|
||||||
|
|
||||||
|
#endif // SERVER_H__
|
||||||
BIN
Socket_snippet/socket
Executable file
BIN
Socket_snippet/socket
Executable file
Binary file not shown.
213
Socket_snippet/socket.c
Normal file
213
Socket_snippet/socket.c
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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 <ctype.h> // isspace
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/un.h> // unix socket
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "cmdlnopts.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief start_socket - create socket and run client or server
|
||||||
|
* @param isserver - TRUE for server, FALSE for client
|
||||||
|
* @param path - UNIX-socket path or local INET socket port
|
||||||
|
* @param isnet - TRUE for INET socket, FALSE for UNIX
|
||||||
|
* @return 0 if OK
|
||||||
|
*/
|
||||||
|
int start_socket(int isserver, char *path, int isnet){
|
||||||
|
if(!path) return 1;
|
||||||
|
DBG("path/port: %s", path);
|
||||||
|
int sock = -1;
|
||||||
|
struct addrinfo hints = {0}, *res;
|
||||||
|
struct sockaddr_un unaddr = {0};
|
||||||
|
if(isnet){
|
||||||
|
DBG("Network socket");
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
if(getaddrinfo("127.0.0.1", path, &hints, &res) != 0){
|
||||||
|
ERR("getaddrinfo");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
DBG("UNIX socket");
|
||||||
|
char apath[128];
|
||||||
|
if(*path == 0){
|
||||||
|
DBG("convert name");
|
||||||
|
apath[0] = 0;
|
||||||
|
strncpy(apath+1, path+1, 126);
|
||||||
|
}else if(strncmp("\\0", path, 2) == 0){
|
||||||
|
DBG("convert name");
|
||||||
|
apath[0] = 0;
|
||||||
|
strncpy(apath+1, path+2, 126);
|
||||||
|
}else strcpy(apath, path);
|
||||||
|
unaddr.sun_family = AF_UNIX;
|
||||||
|
hints.ai_addr = (struct sockaddr*) &unaddr;
|
||||||
|
hints.ai_addrlen = sizeof(unaddr);
|
||||||
|
memcpy(unaddr.sun_path, apath, 106); // if sun_path[0] == 0 we don't create a file
|
||||||
|
hints.ai_family = AF_UNIX;
|
||||||
|
hints.ai_socktype = SOCK_SEQPACKET;
|
||||||
|
res = &hints;
|
||||||
|
}
|
||||||
|
for(struct addrinfo *p = res; p; p = p->ai_next){
|
||||||
|
if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0){ // or SOCK_STREAM?
|
||||||
|
LOGWARN("socket()");
|
||||||
|
WARN("socket()");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(isserver){
|
||||||
|
int reuseaddr = 1;
|
||||||
|
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){
|
||||||
|
LOGWARN("setsockopt()");
|
||||||
|
WARN("setsockopt()");
|
||||||
|
close(sock); sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){
|
||||||
|
LOGWARN("bind()");
|
||||||
|
WARN("bind()");
|
||||||
|
close(sock); sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int enable = 1;
|
||||||
|
if(ioctl(sock, FIONBIO, (void *)&enable) < 0){ // make socket nonblocking
|
||||||
|
LOGERR("Can't make socket nonblocking");
|
||||||
|
ERRX("ioctl()");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){
|
||||||
|
LOGWARN("connect()");
|
||||||
|
WARN("connect()");
|
||||||
|
close(sock); sock = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(sock < 0){
|
||||||
|
LOGERR("Can't open socket");
|
||||||
|
ERRX("Can't open socket");
|
||||||
|
}
|
||||||
|
if(isnet) freeaddrinfo(res);
|
||||||
|
if(isserver) server(sock);
|
||||||
|
else client(sock);
|
||||||
|
close(sock);
|
||||||
|
signals(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// simple wrapper over write: add missed newline and log data
|
||||||
|
void sendmessage(int fd, const char *msg, int l){
|
||||||
|
if(fd < 1 || !msg || l < 1) return;
|
||||||
|
DBG("send to fd %d: %s [%d]", fd, msg, l);
|
||||||
|
char *tmpbuf = MALLOC(char, l+1);
|
||||||
|
memcpy(tmpbuf, msg, l);
|
||||||
|
if(msg[l-1] != '\n') tmpbuf[l++] = '\n';
|
||||||
|
if(l != write(fd, tmpbuf, l)){
|
||||||
|
LOGWARN("write()");
|
||||||
|
WARN("write()");
|
||||||
|
}else{
|
||||||
|
if(globlog){ // logging turned ON
|
||||||
|
tmpbuf[l-1] = 0; // remove trailing '\n' for logging
|
||||||
|
LOGMSG("SEND to fd %d: %s", fd, tmpbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FREE(tmpbuf);
|
||||||
|
}
|
||||||
|
void sendstrmessage(int fd, const char *msg){
|
||||||
|
if(fd < 1 || !msg) return;
|
||||||
|
int l = strlen(msg);
|
||||||
|
sendmessage(fd, msg, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
// text messages for `hresult`
|
||||||
|
static const char *resmessages[] = {
|
||||||
|
[RESULT_OK] = "OK",
|
||||||
|
[RESULT_FAIL] = "FAIL",
|
||||||
|
[RESULT_BADKEY] = "BADKEY",
|
||||||
|
[RESULT_BADVAL] = "BADVAL",
|
||||||
|
[RESULT_SILENCE] = "",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *hresult2str(hresult r){
|
||||||
|
if(r >= RESULT_NUM) return "BADRESULT";
|
||||||
|
return resmessages[r];
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse string of data (command or key=val)
|
||||||
|
// the CONTENT of buffer `str` WILL BE BROKEN!
|
||||||
|
static void parsestring(int fd, handleritem *handlers, char *str){
|
||||||
|
if(fd < 1 || !handlers || !handlers->key || !str || !*str) return;
|
||||||
|
DBG("Got string %s", str);
|
||||||
|
// remove starting spaces in key
|
||||||
|
while(isspace(*str)) ++str;
|
||||||
|
char *val = strchr(str, '=');
|
||||||
|
if(val){ // get value: remove starting spaces in val
|
||||||
|
*val++ = 0;
|
||||||
|
while(isspace(*val)) ++val;
|
||||||
|
}
|
||||||
|
// remove trailing spaces in key
|
||||||
|
char *e = str + strlen(str) - 1; // last key symbol
|
||||||
|
while(isspace(*e) && e > str) --e;
|
||||||
|
e[1] = 0;
|
||||||
|
// now we have key (`str`) and val (or NULL)
|
||||||
|
DBG("key=%s, val=%s", str, val);
|
||||||
|
for(handleritem *h = handlers; h->handler; ++h){
|
||||||
|
if(strcmp(str, h->key) == 0){ // found command
|
||||||
|
if(h->handler){
|
||||||
|
hresult r = h->handler(fd, str, val);
|
||||||
|
sendstrmessage(fd, hresult2str(r));
|
||||||
|
}else sendstrmessage(fd, resmessages[RESULT_FAIL]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendstrmessage(fd, resmessages[RESULT_BADKEY]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief processData - read (if available) data from fd and run processing, sending to fd messages for each command
|
||||||
|
* @param fd - socket file descriptor
|
||||||
|
* @param handlers - NULL-terminated array of handlers
|
||||||
|
* @param buf (io) - zero-terminated buffer for storing rest of data (without newline), its content will be changed
|
||||||
|
* @param buflen - its length
|
||||||
|
* @return FALSE if client closed (nothing to read)
|
||||||
|
*/
|
||||||
|
int processData(int fd, handleritem *handlers, char *buf, int buflen){
|
||||||
|
int curlen = strlen(buf);
|
||||||
|
if(curlen == buflen-1) curlen = 0; // buffer overflow - clear old content
|
||||||
|
ssize_t rd = read(fd, buf + curlen, buflen-1 - curlen);
|
||||||
|
if(rd <= 0) return FALSE;
|
||||||
|
DBG("got %s[%zd] from %d", buf, rd, fd);
|
||||||
|
char *restofdata = buf, *eptr = buf + curlen + rd;
|
||||||
|
*eptr = 0;
|
||||||
|
do{
|
||||||
|
char *nl = strchr(restofdata, '\n');
|
||||||
|
if(!nl) break;
|
||||||
|
*nl++ = 0;
|
||||||
|
parsestring(fd, handlers, restofdata);
|
||||||
|
restofdata = nl;
|
||||||
|
DBG("rest of data: %s", restofdata);
|
||||||
|
}while(1);
|
||||||
|
if(restofdata != buf) memmove(buf, restofdata, eptr - restofdata + 1);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
56
Socket_snippet/socket.h
Normal file
56
Socket_snippet/socket.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the socksnippet 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__
|
||||||
|
|
||||||
|
// max & min TCP socket port number
|
||||||
|
#define PORTN_MAX (65535)
|
||||||
|
#define PORTN_MIN (1024)
|
||||||
|
|
||||||
|
#define BUFLEN (1024)
|
||||||
|
// Max amount of connections
|
||||||
|
#define MAXCLIENTS (30)
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
RESULT_OK, // all OK
|
||||||
|
RESULT_FAIL, // failed running command
|
||||||
|
RESULT_BADVAL, // bad key's value
|
||||||
|
RESULT_BADKEY, // bad key
|
||||||
|
RESULT_SILENCE, // send nothing to client
|
||||||
|
RESULT_NUM
|
||||||
|
} hresult;
|
||||||
|
|
||||||
|
const char *hresult2str(hresult r);
|
||||||
|
|
||||||
|
// fd - socket fd to send private messages, key, val - key and its value
|
||||||
|
typedef hresult (*mesghandler)(int fd, const char *key, const char *val);
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
mesghandler handler;
|
||||||
|
const char *key;
|
||||||
|
} handleritem;
|
||||||
|
|
||||||
|
int start_socket(int server, char *path, int isnet);
|
||||||
|
void sendmessage(int fd, const char *msg, int l);
|
||||||
|
void sendstrmessage(int fd, const char *msg);
|
||||||
|
|
||||||
|
int processData(int fd, handleritem *handlers, char *buf, int buflen);
|
||||||
|
|
||||||
|
#endif // SERSOCK_H__
|
||||||
1
Socket_snippet/socksnippet.cflags
Normal file
1
Socket_snippet/socksnippet.cflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c17
|
||||||
6
Socket_snippet/socksnippet.config
Normal file
6
Socket_snippet/socksnippet.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
Socket_snippet/socksnippet.creator
Normal file
1
Socket_snippet/socksnippet.creator
Normal file
@ -0,0 +1 @@
|
|||||||
|
[General]
|
||||||
163
Socket_snippet/socksnippet.creator.user
Normal file
163
Socket_snippet/socksnippet.creator.user
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE QtCreatorProject>
|
||||||
|
<!-- Written by QtCreator 6.0.0, 2022-02-02T17:26:10. -->
|
||||||
|
<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 type="QVariantMap" key="CppEditor.QuickFix">
|
||||||
|
<value type="bool" key="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_CANserver</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"/>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||||
|
<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_snippet/socksnippet.cxxflags
Normal file
1
Socket_snippet/socksnippet.cxxflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c++17
|
||||||
9
Socket_snippet/socksnippet.files
Normal file
9
Socket_snippet/socksnippet.files
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
client.c
|
||||||
|
client.h
|
||||||
|
cmdlnopts.c
|
||||||
|
cmdlnopts.h
|
||||||
|
main.c
|
||||||
|
server.c
|
||||||
|
server.h
|
||||||
|
socket.c
|
||||||
|
socket.h
|
||||||
1
Socket_snippet/socksnippet.includes
Normal file
1
Socket_snippet/socksnippet.includes
Normal file
@ -0,0 +1 @@
|
|||||||
|
.
|
||||||
11
Socket_snippet/testcommands
Normal file
11
Socket_snippet/testcommands
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
time
|
||||||
|
getval1
|
||||||
|
setval1 = 56
|
||||||
|
getval2
|
||||||
|
setval2 = 189
|
||||||
|
getval1 = asdf
|
||||||
|
getval2 = 000000asdffd fdassdf fda
|
||||||
|
time
|
||||||
|
a
|
||||||
|
getval1
|
||||||
|
getval2
|
||||||
Loading…
x
Reference in New Issue
Block a user