parent
							
								
									c1b6566cda
								
							
						
					
					
						commit
						ed4d54a510
					
				@ -0,0 +1,57 @@ | 
				
			||||
--- | 
				
			||||
Language: Cpp | 
				
			||||
BasedOnStyle: LLVM | 
				
			||||
AccessModifierOffset: -4 | 
				
			||||
AlignConsecutiveAssignments: false | 
				
			||||
AlignConsecutiveDeclarations: false | 
				
			||||
AlignOperands: true | 
				
			||||
AlignTrailingComments: false | 
				
			||||
AlwaysBreakTemplateDeclarations: Yes | 
				
			||||
BraceWrapping:  | 
				
			||||
  AfterCaseLabel: false | 
				
			||||
  AfterClass: false | 
				
			||||
  AfterControlStatement: false | 
				
			||||
  AfterEnum: false | 
				
			||||
  AfterFunction: false | 
				
			||||
  AfterNamespace: false | 
				
			||||
  AfterStruct: false | 
				
			||||
  AfterUnion: false | 
				
			||||
  AfterExternBlock: false | 
				
			||||
  BeforeCatch: false | 
				
			||||
  BeforeElse: false | 
				
			||||
  BeforeLambdaBody: false | 
				
			||||
  BeforeWhile: false | 
				
			||||
  SplitEmptyFunction: true | 
				
			||||
  SplitEmptyRecord: true | 
				
			||||
  SplitEmptyNamespace: true | 
				
			||||
BreakBeforeBraces: Custom | 
				
			||||
BreakConstructorInitializers: AfterColon | 
				
			||||
BreakConstructorInitializersBeforeComma: false | 
				
			||||
ColumnLimit: 120 | 
				
			||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false | 
				
			||||
ContinuationIndentWidth: 8 | 
				
			||||
IncludeCategories:  | 
				
			||||
  - Regex: '^<.*' | 
				
			||||
    Priority: 1 | 
				
			||||
  - Regex: '^".*' | 
				
			||||
    Priority: 2 | 
				
			||||
  - Regex: '.*' | 
				
			||||
    Priority: 3 | 
				
			||||
IncludeIsMainRegex: '([-_](test|unittest))?$' | 
				
			||||
IndentCaseLabels: true | 
				
			||||
IndentWidth: 4 | 
				
			||||
InsertNewlineAtEOF: true | 
				
			||||
MacroBlockBegin: '' | 
				
			||||
MacroBlockEnd: '' | 
				
			||||
MaxEmptyLinesToKeep: 2 | 
				
			||||
NamespaceIndentation: All | 
				
			||||
SpaceAfterCStyleCast: true | 
				
			||||
SpaceAfterTemplateKeyword: false | 
				
			||||
SpaceBeforeRangeBasedForLoopColon: false | 
				
			||||
SpaceInEmptyParentheses: false | 
				
			||||
SpacesInAngles: false | 
				
			||||
SpacesInConditionalStatement: false | 
				
			||||
SpacesInCStyleCastParentheses: false | 
				
			||||
SpacesInParentheses: false | 
				
			||||
TabWidth: 4 | 
				
			||||
... | 
				
			||||
@ -0,0 +1,34 @@ | 
				
			||||
#include "hexdump.h" | 
				
			||||
 | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <stdio.h> | 
				
			||||
 | 
				
			||||
/* https://gist.github.com/ccbrown/9722406 */ | 
				
			||||
void hexdump(const void *data, const size_t size) { | 
				
			||||
    char ascii[17]; | 
				
			||||
    ascii[16] = '\0'; | 
				
			||||
    for (size_t i = 0; i < size; ++i) { | 
				
			||||
        printf("%02X ", ((unsigned char *) data)[i]); | 
				
			||||
        const uint8_t c = ((unsigned char *) data)[i]; | 
				
			||||
        if (c >= ' ' && c <= '~') { | 
				
			||||
            ascii[i % 16] = (char) c; | 
				
			||||
        } else { | 
				
			||||
            ascii[i % 16] = '.'; | 
				
			||||
        } | 
				
			||||
        if ((i + 1) % 8 == 0 || i + 1 == size) { | 
				
			||||
            printf(" "); | 
				
			||||
            if ((i + 1) % 16 == 0) { | 
				
			||||
                printf("|  %s \n", ascii); | 
				
			||||
            } else if (i + 1 == size) { | 
				
			||||
                ascii[(i + 1) % 16] = '\0'; | 
				
			||||
                if ((i + 1) % 16 <= 8) { | 
				
			||||
                    printf(" "); | 
				
			||||
                } | 
				
			||||
                for (size_t j = (i + 1) % 16; j < 16; ++j) { | 
				
			||||
                    printf("   "); | 
				
			||||
                } | 
				
			||||
                printf("|  %s \n", ascii); | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,8 @@ | 
				
			||||
#ifndef HEXDUMP_H | 
				
			||||
#define HEXDUMP_H | 
				
			||||
 | 
				
			||||
#include <stddef.h> | 
				
			||||
 | 
				
			||||
void hexdump(const void *data, size_t size); | 
				
			||||
 | 
				
			||||
#endif //HEXDUMP_H
 | 
				
			||||
@ -0,0 +1,125 @@ | 
				
			||||
#include <stdio.h> | 
				
			||||
#include "modbus.h" | 
				
			||||
#include "hexdump.h" | 
				
			||||
#include "parsehex.h" | 
				
			||||
 | 
				
			||||
ModbusException_t soa(ModbusSlave_t *ms, ModbusFunction_t fcx, uint8_t slave_id) { | 
				
			||||
    printf("Start of access: fc%02d, slave %d\n", fcx, slave_id); | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
void eoa(ModbusSlave_t *ms) { | 
				
			||||
    printf("End of access\n"); | 
				
			||||
} | 
				
			||||
ModbusException_t rh(ModbusSlave_t *ms, uint16_t i, uint16_t *out) { | 
				
			||||
    printf("rh %d\n", i); | 
				
			||||
    switch (i) { | 
				
			||||
        case 107: | 
				
			||||
            *out = 0xAE41; | 
				
			||||
            break; | 
				
			||||
        case 108: | 
				
			||||
            *out = 0x5652; | 
				
			||||
            break; | 
				
			||||
        case 109: | 
				
			||||
            *out = 0x4340; | 
				
			||||
            break; | 
				
			||||
        default: | 
				
			||||
            return MB_EXCEPTION_ILLEGAL_DATA_ADDRESS; | 
				
			||||
    } | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
ModbusException_t ri(ModbusSlave_t *ms, uint16_t i, uint16_t *out) { | 
				
			||||
    printf("ri %d\n", i); | 
				
			||||
    switch (i) { | 
				
			||||
        case 8: | 
				
			||||
            *out = 0xa; | 
				
			||||
            break; | 
				
			||||
        default: | 
				
			||||
            return MB_EXCEPTION_ILLEGAL_DATA_ADDRESS; | 
				
			||||
    } | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
ModbusException_t rc(ModbusSlave_t *ms, uint16_t i, bool *out) { | 
				
			||||
    uint8_t store[] = { | 
				
			||||
        0b11001101, | 
				
			||||
        0b01101011, | 
				
			||||
        0b10110010, | 
				
			||||
        0b00001110, | 
				
			||||
        0b00011011, | 
				
			||||
    }; | 
				
			||||
 | 
				
			||||
    if (i >= 19 && i <= 55) { | 
				
			||||
        int pos = i-19; | 
				
			||||
        *out = 0 != (store[pos/8] & (1 << (pos%8))); | 
				
			||||
    } else { | 
				
			||||
        return MB_EXCEPTION_ILLEGAL_DATA_ADDRESS; | 
				
			||||
    } | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
ModbusException_t rd(ModbusSlave_t *ms, uint16_t i, bool *out) { | 
				
			||||
    uint8_t store[] = { | 
				
			||||
            0b10101100, | 
				
			||||
            0b11011011, | 
				
			||||
            0b00110101, | 
				
			||||
    }; | 
				
			||||
 | 
				
			||||
    if (i >= 196 && i <= 217) { | 
				
			||||
        int pos = i - 196; | 
				
			||||
        *out = 0 != (store[pos/8] & (1 << (pos%8))); | 
				
			||||
    } else { | 
				
			||||
        return MB_EXCEPTION_ILLEGAL_DATA_ADDRESS; | 
				
			||||
    } | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
ModbusException_t wc(ModbusSlave_t *pSlave, uint16_t i, bool b) { | 
				
			||||
    printf("Write coil %d <- %d\n", i, b); | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
ModbusException_t wh(ModbusSlave_t *pSlave, uint16_t i, uint16_t i1) { | 
				
			||||
    printf("Write reg %d <- %d\n", i, i1); | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
int main() | 
				
			||||
{ | 
				
			||||
#define buflen 1024 | 
				
			||||
    uint8_t buf[buflen]; | 
				
			||||
    uint8_t buf2[buflen]; | 
				
			||||
 | 
				
			||||
    // 11 03 006B 0003 7687
 | 
				
			||||
    // 11 04 0008 0001 B298
 | 
				
			||||
    // 11 01 0013 0025 0E84
 | 
				
			||||
    // 11 02 00C4 0016 BAA9
 | 
				
			||||
    // 11 05 00AC FF00 4E8B
 | 
				
			||||
    // 11 06 0001 0003 9A9B
 | 
				
			||||
    // 11 0F 0013 000A 02 CD01 BF0B
 | 
				
			||||
    // 11 10 0001 0002 04 000A 0102 C6F0
 | 
				
			||||
    ssize_t pldlen = parsehex("11 03 006B 0003 7687", buf, buflen); | 
				
			||||
 | 
				
			||||
    ModbusSlave_t ms = { | 
				
			||||
           .addr = 17, | 
				
			||||
           .proto = MB_PROTO_RTU, | 
				
			||||
           .startOfAccess = soa, | 
				
			||||
           .endOfAccess = eoa, | 
				
			||||
           .readHolding = rh, | 
				
			||||
           .readInput = ri, | 
				
			||||
           .readCoil = rc, | 
				
			||||
           .readDiscrete = rd, | 
				
			||||
           .writeCoil = wc, | 
				
			||||
           .writeHolding = wh, | 
				
			||||
    }; | 
				
			||||
 | 
				
			||||
    printf("Req:\n"); | 
				
			||||
    hexdump(buf, pldlen); | 
				
			||||
 | 
				
			||||
    size_t respsize; | 
				
			||||
    ModbusError_t e = mb_handleRequest(&ms, buf, pldlen, buf2, buflen, &respsize); | 
				
			||||
    if (e) { | 
				
			||||
        printf("Err %d\n", e); | 
				
			||||
    } else { | 
				
			||||
        printf("Resp:\n"); | 
				
			||||
        hexdump(buf2, respsize); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
@ -0,0 +1,37 @@ | 
				
			||||
#include "parsehex.h" | 
				
			||||
#include <stdbool.h> | 
				
			||||
 | 
				
			||||
ssize_t parsehex(const char *s, uint8_t *out, size_t cap) | 
				
			||||
{ | 
				
			||||
    uint8_t buf = 0; | 
				
			||||
    uint8_t v; | 
				
			||||
    bool first = true; | 
				
			||||
    char c; | 
				
			||||
    size_t sz = 0; | 
				
			||||
    while (0 != (c = *s++)) { | 
				
			||||
        if (c >= '0' && c <= '9') { | 
				
			||||
            v = c - '0'; | 
				
			||||
        } else if (c >= 'a' && c <= 'f') { | 
				
			||||
            v = 10 + (c - 'a'); | 
				
			||||
        } else if (c >= 'A' && c <= 'F') { | 
				
			||||
            v = 10 + (c - 'A'); | 
				
			||||
        } else { | 
				
			||||
            continue; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        if (first) { | 
				
			||||
            buf |= (v & 15) << 4; | 
				
			||||
            first = false; | 
				
			||||
        } else { | 
				
			||||
            buf |= (v & 15); | 
				
			||||
            if (cap == 0) { | 
				
			||||
                return -1; | 
				
			||||
            } | 
				
			||||
            out[sz++] = buf; | 
				
			||||
            buf = 0; | 
				
			||||
            first = true; | 
				
			||||
            cap--; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
    return (ssize_t) sz; | 
				
			||||
} | 
				
			||||
@ -0,0 +1,9 @@ | 
				
			||||
#ifndef PARSEHEX_H | 
				
			||||
#define PARSEHEX_H | 
				
			||||
 | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <stdio.h> | 
				
			||||
 | 
				
			||||
ssize_t parsehex(const char *s, uint8_t *out, size_t cap); | 
				
			||||
 | 
				
			||||
#endif //PARSEHEX_H
 | 
				
			||||
@ -0,0 +1,419 @@ | 
				
			||||
/**
 | 
				
			||||
 * \file stcpsc.c | 
				
			||||
 * \brief Simple-to-use TCP server/client | 
				
			||||
 * \author Petr Svoboda, 2014-10-11 | 
				
			||||
 * | 
				
			||||
 * 2024 - removed protocol handling, just using it to send and receive raw frames. Added static. | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include "stcpsc.h" | 
				
			||||
#include <arpa/inet.h> | 
				
			||||
#include <errno.h> | 
				
			||||
#include <netdb.h> | 
				
			||||
#include <netinet/in.h> | 
				
			||||
#include <pthread.h> | 
				
			||||
#include <semaphore.h> | 
				
			||||
#include <stdio.h> | 
				
			||||
#include <stdlib.h> | 
				
			||||
#include <string.h> | 
				
			||||
#include <sys/socket.h> | 
				
			||||
#include <sys/types.h> | 
				
			||||
#include <unistd.h> | 
				
			||||
 | 
				
			||||
#define STCP_MAX_MSG_SIZE 2048 | 
				
			||||
#define STCP_HOST_ADR_LEN 100 | 
				
			||||
 | 
				
			||||
#define STCP_READ_ERR_NO 0 | 
				
			||||
#define STCP_READ_ERR_CLOSE STCP_DISCONNECT_REASON_CLOSED | 
				
			||||
#define STCP_READ_ERR_READ STCP_DISCONNECT_REASON_ERROR | 
				
			||||
#define STCP_READ_ERR_INTERNAL STCP_DISCONNECT_REASON_INTERNAL | 
				
			||||
#define STCP_READ_ERR_MTU STCP_DISCONNECT_REASON_MTU | 
				
			||||
#define STCP_READ_ERR_KICK STCP_DISCONNECT_REASON_KICK | 
				
			||||
 | 
				
			||||
struct simple_tcp_queue; | 
				
			||||
typedef struct simple_tcp_queue simple_tcp_queue_t; | 
				
			||||
 | 
				
			||||
struct simple_tcp_queue { | 
				
			||||
    int cli_fd, mtu; | 
				
			||||
    msg_received_fce_t cli_rec_fce; | 
				
			||||
    simple_tcp_queue_t *next; | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/* Server stuff */ | 
				
			||||
static volatile int srv_done = 0; | 
				
			||||
static unsigned short srv_port = 1234; | 
				
			||||
static int srv_mtu = -1; | 
				
			||||
static simple_tcp_queue_t *srv_queue = NULL; | 
				
			||||
static pthread_t server_thread = 0; | 
				
			||||
static fd_set active_fd_set; | 
				
			||||
 | 
				
			||||
static msg_received_fce_t srv_rec_fce = NULL; | 
				
			||||
static cli_connected_fce_t srv_conn_fce = NULL; | 
				
			||||
static cli_disconnected_fce_t srv_disconn_fce = NULL; | 
				
			||||
 | 
				
			||||
/* Client stuff */ | 
				
			||||
static sem_t cli_conn_sem; | 
				
			||||
static int tcpcli_portno; | 
				
			||||
static int client_mtu = -1; | 
				
			||||
static volatile int tcpcli_sockfd = -1; | 
				
			||||
static volatile int cli_thread_done = 0; | 
				
			||||
static pthread_t client_thread; | 
				
			||||
static char cli_host_address[STCP_HOST_ADR_LEN + 1]; | 
				
			||||
 | 
				
			||||
static msg_received_fce_t cli_rec_fce = NULL; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
bool simple_tcp_client_ended() { return cli_thread_done; } | 
				
			||||
 | 
				
			||||
bool simple_tcp_server_ended() { return srv_done; } | 
				
			||||
 | 
				
			||||
static int make_server_socket() { | 
				
			||||
    int server_sock; | 
				
			||||
    struct sockaddr_in name; | 
				
			||||
    int yes = 1; | 
				
			||||
 | 
				
			||||
    /* Create the socket. */ | 
				
			||||
    server_sock = socket(PF_INET, SOCK_STREAM, 0); | 
				
			||||
    if (server_sock < 0) { | 
				
			||||
        printf("TCPSRV: socket err\n"); | 
				
			||||
        return -1; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // tento radek zpusobi, ze pri opakovanem restartu serveru, bude volani
 | 
				
			||||
    // funkce bind() uspesne, kdo neveri, at ho zakomentuje :))
 | 
				
			||||
    if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { | 
				
			||||
        printf("TCPSRV: setsockopt err\n"); | 
				
			||||
        return -1; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /* Give the socket a name. */ | 
				
			||||
    name.sin_family = AF_INET; | 
				
			||||
    name.sin_port = htons(srv_port); | 
				
			||||
    name.sin_addr.s_addr = htonl(INADDR_ANY); | 
				
			||||
    if (bind(server_sock, (struct sockaddr *) &name, sizeof(name)) < 0) { | 
				
			||||
        printf("TCPSRV: bind err\n"); | 
				
			||||
        return -1; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return server_sock; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static void close_client(int fd, int reason) { | 
				
			||||
    simple_tcp_queue_t *toDel = srv_queue; | 
				
			||||
    simple_tcp_queue_t **prev = &srv_queue; | 
				
			||||
    while (toDel) { | 
				
			||||
        if (toDel->cli_fd == fd) { | 
				
			||||
            /* match! */ | 
				
			||||
            simple_tcp_queue_t *next = toDel->next; | 
				
			||||
            free(toDel); | 
				
			||||
            *prev = next; | 
				
			||||
            break; | 
				
			||||
        } | 
				
			||||
        /* iterate */ | 
				
			||||
        prev = &(toDel->next); | 
				
			||||
        toDel = toDel->next; | 
				
			||||
    } | 
				
			||||
    FD_CLR(fd, &active_fd_set); /* Remove the client from the set */ | 
				
			||||
    close(fd); | 
				
			||||
    if (srv_disconn_fce) | 
				
			||||
        srv_disconn_fce(fd, reason); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static int read_from_client(simple_tcp_queue_t *cli) { | 
				
			||||
    if (cli == NULL) { | 
				
			||||
        return STCP_READ_ERR_INTERNAL; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    // limitation - it must all come in one frame!
 | 
				
			||||
    unsigned char buff[cli->mtu]; | 
				
			||||
    int readed = recv(cli->cli_fd, buff, STCP_MAX_MSG_SIZE + 2, 0); | 
				
			||||
 | 
				
			||||
    simple_msg_t msg = { | 
				
			||||
            .data = buff, | 
				
			||||
            .len = readed, | 
				
			||||
    }; | 
				
			||||
 | 
				
			||||
    if (cli->cli_rec_fce(cli->cli_fd, &msg)) { | 
				
			||||
        return STCP_READ_ERR_KICK; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return STCP_READ_ERR_NO; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static int read_from_srv_fd(int filedes) { | 
				
			||||
    simple_tcp_queue_t *cli = srv_queue; | 
				
			||||
    while (cli) { | 
				
			||||
        if (cli->cli_fd == filedes) { | 
				
			||||
            break; | 
				
			||||
        } | 
				
			||||
        cli = cli->next; | 
				
			||||
    } | 
				
			||||
    return read_from_client(cli); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static void *srv_thread_function(void *arg) { | 
				
			||||
    struct timeval tim; | 
				
			||||
    int server_sock; | 
				
			||||
    fd_set read_fd_set; | 
				
			||||
    int fd, s_rv; | 
				
			||||
    struct sockaddr_in clientname; | 
				
			||||
    socklen_t size; | 
				
			||||
    printf("srv_thread_function\n"); | 
				
			||||
 | 
				
			||||
    /* unused */ | 
				
			||||
    (void) arg; | 
				
			||||
 | 
				
			||||
    /* Create the socket and set it up to accept connections. */ | 
				
			||||
    server_sock = make_server_socket(); | 
				
			||||
    if (server_sock < 0) { | 
				
			||||
        printf("TCPSRV: fail to create server socket\n"); | 
				
			||||
        return NULL; | 
				
			||||
    } | 
				
			||||
    printf("Socket bound\n"); | 
				
			||||
 | 
				
			||||
    if (listen(server_sock, 1) < 0) { | 
				
			||||
        printf("TCPSRV: listen ERROR\n"); | 
				
			||||
        return NULL; | 
				
			||||
    } | 
				
			||||
    printf("Server awaiting clients...\n"); | 
				
			||||
 | 
				
			||||
    /* Initialize the set of active sockets. */ | 
				
			||||
    FD_ZERO(&active_fd_set); | 
				
			||||
    FD_SET(server_sock, &active_fd_set); | 
				
			||||
 | 
				
			||||
    while (!srv_done) { | 
				
			||||
        /* 200ms timeout */ | 
				
			||||
        tim.tv_sec = 0; | 
				
			||||
        tim.tv_usec = 200000; | 
				
			||||
        /* Block until input arrives on one or more active sockets. */ | 
				
			||||
        read_fd_set = active_fd_set; | 
				
			||||
        s_rv = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tim); | 
				
			||||
 | 
				
			||||
        if (s_rv == 0) { | 
				
			||||
            continue; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        if (s_rv < 0) { | 
				
			||||
            printf("TCPSRV: server select ERROR\n"); | 
				
			||||
            return NULL; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        printf("TCPSRV: client selected\n"); | 
				
			||||
        /* Service all the sockets with input pending. */ | 
				
			||||
        for (fd = 0; fd < FD_SETSIZE; ++fd) { | 
				
			||||
            if (FD_ISSET(fd, &read_fd_set)) { | 
				
			||||
                if (fd == server_sock) { | 
				
			||||
                    /* Connection request on original socket. */ | 
				
			||||
                    int novy; | 
				
			||||
                    size = sizeof(clientname); | 
				
			||||
                    novy = accept(server_sock, (struct sockaddr *) &clientname, &size); | 
				
			||||
                    if (novy < 0) { | 
				
			||||
                        printf("TCPSRV: server accept ERROR\n"); | 
				
			||||
                        return NULL; | 
				
			||||
                    } | 
				
			||||
                    printf("TCPSRV: client accepted\n"); | 
				
			||||
 | 
				
			||||
                    FD_SET(novy, &active_fd_set); /* Add new client to the set */ | 
				
			||||
                    simple_tcp_queue_t *cliq = (simple_tcp_queue_t *) malloc(sizeof(simple_tcp_queue_t)); | 
				
			||||
                    cliq->cli_fd = novy; | 
				
			||||
                    cliq->next = srv_queue; | 
				
			||||
                    cliq->mtu = srv_mtu; | 
				
			||||
                    cliq->cli_rec_fce = srv_rec_fce; | 
				
			||||
                    srv_queue = cliq; | 
				
			||||
 | 
				
			||||
                    if (srv_conn_fce) { | 
				
			||||
                        if (srv_conn_fce(novy, inet_ntoa(clientname.sin_addr))) { | 
				
			||||
                            close_client(novy, STCP_DISCONNECT_REASON_KICK); | 
				
			||||
                        } | 
				
			||||
                    } | 
				
			||||
                } else { | 
				
			||||
                    /* Data arriving on an already-connected socket. */ | 
				
			||||
                    printf("TCPSRV: receiving data from client\n"); | 
				
			||||
                    int crv = read_from_srv_fd(fd); | 
				
			||||
                    if (crv != STCP_READ_ERR_NO) { | 
				
			||||
                        close_client(fd, crv); | 
				
			||||
                    } | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /* Close all open sockets */ | 
				
			||||
    for (fd = 0; fd < FD_SETSIZE; ++fd) { | 
				
			||||
        if (FD_ISSET(fd, &read_fd_set)) { | 
				
			||||
            close_client(fd, STCP_DISCONNECT_REASON_SERVER_CLOSE); | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
    return NULL; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static void *cli_thread_function(void *arg) { | 
				
			||||
    struct timeval tim; | 
				
			||||
    struct sockaddr_in host_addr; | 
				
			||||
    struct hostent *host_ent; | 
				
			||||
    fd_set active_fd_set; | 
				
			||||
    fd_set read_fd_set; | 
				
			||||
    int fd, s_rv; | 
				
			||||
    char host_ip_str[INET_ADDRSTRLEN]; | 
				
			||||
 | 
				
			||||
    /* unused */ | 
				
			||||
    (void) arg; | 
				
			||||
 | 
				
			||||
    tcpcli_sockfd = -1; | 
				
			||||
 | 
				
			||||
    /* Create a socket point */ | 
				
			||||
    tcpcli_sockfd = socket(AF_INET, SOCK_STREAM, 0); | 
				
			||||
    if (tcpcli_sockfd < 0) { | 
				
			||||
        printf("TCPCL: error opening socket\n"); | 
				
			||||
        sem_post(&cli_conn_sem); | 
				
			||||
        return NULL; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    host_ent = gethostbyname(cli_host_address); | 
				
			||||
    if (host_ent == NULL) { | 
				
			||||
        printf("TCPCL: error '%s': no such host\n", cli_host_address); | 
				
			||||
        tcpcli_sockfd = -1; | 
				
			||||
        sem_post(&cli_conn_sem); | 
				
			||||
        return NULL; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    memset(&host_addr, 0, sizeof(host_addr)); | 
				
			||||
    host_addr.sin_family = AF_INET; | 
				
			||||
    host_addr.sin_port = htons(tcpcli_portno); | 
				
			||||
    memcpy(&host_addr.sin_addr.s_addr, host_ent->h_addr, host_ent->h_length); | 
				
			||||
    inet_ntop(AF_INET, &(host_addr.sin_addr), host_ip_str, INET_ADDRSTRLEN); | 
				
			||||
 | 
				
			||||
    printf("TCPCL: connecting to %s:%d\n", host_ip_str, tcpcli_portno); | 
				
			||||
    /* Now connect to the server */ | 
				
			||||
    if (connect(tcpcli_sockfd, (struct sockaddr *) &host_addr, sizeof(host_addr)) < 0) { | 
				
			||||
        printf("TCPCL: error connect to: %s:%d\n", host_ip_str, tcpcli_portno); | 
				
			||||
        printf("error: %s\n", strerror(errno)); | 
				
			||||
        tcpcli_sockfd = -1; | 
				
			||||
        sem_post(&cli_conn_sem); | 
				
			||||
        return NULL; | 
				
			||||
    } | 
				
			||||
    simple_tcp_queue_t *client_que; | 
				
			||||
 | 
				
			||||
    printf("TCPCL: connected to %s:%d\n", host_ip_str, tcpcli_portno); | 
				
			||||
    sem_post(&cli_conn_sem); | 
				
			||||
 | 
				
			||||
    client_que = (simple_tcp_queue_t *) malloc(sizeof(simple_tcp_queue_t)); | 
				
			||||
    client_que->cli_fd = tcpcli_sockfd; | 
				
			||||
    client_que->next = NULL; | 
				
			||||
    client_que->mtu = client_mtu; | 
				
			||||
    client_que->cli_rec_fce = cli_rec_fce; | 
				
			||||
 | 
				
			||||
    /* Initialize the set of active sockets. */ | 
				
			||||
    FD_ZERO(&active_fd_set); | 
				
			||||
    FD_SET(tcpcli_sockfd, &active_fd_set); | 
				
			||||
 | 
				
			||||
    while (!cli_thread_done) { | 
				
			||||
        /* 200ms timeout */ | 
				
			||||
        tim.tv_sec = 0; | 
				
			||||
        tim.tv_usec = 200000; | 
				
			||||
        /* Block until input arrives on one or more active sockets. */ | 
				
			||||
        read_fd_set = active_fd_set; | 
				
			||||
        s_rv = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tim); | 
				
			||||
 | 
				
			||||
        if (s_rv == 0) { | 
				
			||||
            continue; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        if (s_rv < 0) { | 
				
			||||
            printf("TCPSRV: server select ERROR\n"); | 
				
			||||
            return NULL; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        /* Service all the sockets with input pending. */ | 
				
			||||
        for (fd = 0; fd < FD_SETSIZE; ++fd) { | 
				
			||||
            if (FD_ISSET(fd, &read_fd_set) && fd == tcpcli_sockfd) { | 
				
			||||
                if (read_from_client(client_que) != STCP_READ_ERR_NO) { | 
				
			||||
                    cli_thread_done = 1; | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    free(client_que); | 
				
			||||
    close(tcpcli_sockfd); | 
				
			||||
    tcpcli_sockfd = -1; | 
				
			||||
    return NULL; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
int simple_tcp_server_start(unsigned short port, int mtu, msg_received_fce_t rec, cli_connected_fce_t con, | 
				
			||||
                            cli_disconnected_fce_t dis) { | 
				
			||||
    srv_done = 0; | 
				
			||||
    srv_port = port; | 
				
			||||
    srv_mtu = mtu; | 
				
			||||
    srv_rec_fce = rec; | 
				
			||||
    srv_conn_fce = con; | 
				
			||||
    srv_disconn_fce = dis; | 
				
			||||
    srv_queue = NULL; | 
				
			||||
    if (pthread_create(&server_thread, NULL, srv_thread_function, NULL)) { | 
				
			||||
        printf("Fail to create server thread\n"); | 
				
			||||
        srv_done = 1; | 
				
			||||
        return -1; | 
				
			||||
    } | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
int simple_tcp_server_stop() { | 
				
			||||
    if (srv_done || !server_thread) | 
				
			||||
        return 0; | 
				
			||||
    srv_done = 1; | 
				
			||||
    if (pthread_join(server_thread, NULL)) | 
				
			||||
        return -1; | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
int simple_tcp_client_start(const char *address_port, int mtu, int def_port, msg_received_fce_t rec) { | 
				
			||||
    char *addrtempbuf = strdup(address_port); | 
				
			||||
 | 
				
			||||
    char *portp = strchr(addrtempbuf, ':'); | 
				
			||||
    if (portp) { | 
				
			||||
        *portp = '\0'; | 
				
			||||
        portp++; | 
				
			||||
        tcpcli_portno = atoi((portp)); | 
				
			||||
    } else { | 
				
			||||
        tcpcli_portno = def_port; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    cli_thread_done = 0; | 
				
			||||
    client_mtu = mtu; | 
				
			||||
    cli_rec_fce = rec; | 
				
			||||
    strncpy(cli_host_address, addrtempbuf, STCP_HOST_ADR_LEN); | 
				
			||||
 | 
				
			||||
    free(addrtempbuf); | 
				
			||||
 | 
				
			||||
    if (sem_init(&cli_conn_sem, 0, 0) < 0) { | 
				
			||||
        printf("TCPCL: sem_init\n"); | 
				
			||||
        return -1; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if (pthread_create(&client_thread, NULL, cli_thread_function, NULL)) { | 
				
			||||
        cli_thread_done = 1; | 
				
			||||
        printf("Failed to create pthread"); | 
				
			||||
        return -1; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    sem_wait(&cli_conn_sem); | 
				
			||||
    sem_destroy(&cli_conn_sem); | 
				
			||||
 | 
				
			||||
    return tcpcli_sockfd; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
int simple_tcp_client_done() { | 
				
			||||
    if (cli_thread_done) { | 
				
			||||
        return 0; | 
				
			||||
    } | 
				
			||||
    cli_thread_done = 1; | 
				
			||||
    if (pthread_join(client_thread, NULL)) { | 
				
			||||
        return -1; | 
				
			||||
    } | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
int simple_tcp_send(int fd, const simple_msg_t *msg) { | 
				
			||||
    write(fd, msg->data, msg->len); | 
				
			||||
    return 0; | 
				
			||||
} | 
				
			||||
@ -0,0 +1,39 @@ | 
				
			||||
/**
 | 
				
			||||
 * \file stcpsc.h | 
				
			||||
 * \brief Simple-to-use TCP server/client | 
				
			||||
 * \author Petr Svoboda, 2014-10-11 | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#ifndef SIMPLE_TCP_SERVER_CLI_H | 
				
			||||
#define SIMPLE_TCP_SERVER_CLI_H | 
				
			||||
 | 
				
			||||
#define STCP_DISCONNECT_REASON_CLOSED       -1 | 
				
			||||
#define STCP_DISCONNECT_REASON_ERROR        -2 | 
				
			||||
#define STCP_DISCONNECT_REASON_INTERNAL     -3 | 
				
			||||
#define STCP_DISCONNECT_REASON_MTU          -4 | 
				
			||||
#define STCP_DISCONNECT_REASON_KICK         -5 | 
				
			||||
#define STCP_DISCONNECT_REASON_SERVER_CLOSE -6 | 
				
			||||
 | 
				
			||||
#include <stdbool.h> | 
				
			||||
 | 
				
			||||
typedef struct { | 
				
			||||
  unsigned len; | 
				
			||||
  unsigned char* data; | 
				
			||||
} simple_msg_t; | 
				
			||||
 | 
				
			||||
typedef int  (*msg_received_fce_t)(int fd, const simple_msg_t* msg); | 
				
			||||
typedef int  (*cli_connected_fce_t)(int fd, const char* address); | 
				
			||||
typedef void (*cli_disconnected_fce_t)(int fd, int reason); | 
				
			||||
 | 
				
			||||
int simple_tcp_server_start(unsigned short port, int mtu, msg_received_fce_t rec, cli_connected_fce_t con, cli_disconnected_fce_t dis); | 
				
			||||
int simple_tcp_server_stop(); | 
				
			||||
 | 
				
			||||
int simple_tcp_client_start(const char* address_port, int mtu, int def_port, msg_received_fce_t rec); | 
				
			||||
int simple_tcp_client_done(); | 
				
			||||
 | 
				
			||||
int simple_tcp_send(int fd, const simple_msg_t* msg); | 
				
			||||
 | 
				
			||||
bool simple_tcp_client_ended(); | 
				
			||||
bool simple_tcp_server_ended(); | 
				
			||||
 | 
				
			||||
#endif // SIMPLE_TCP_SERVER_CLI_H
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue