277 lines
9.3 KiB
C
277 lines
9.3 KiB
C
|
/****************************************************************************
|
||
|
* apps/examples/tcp_ipc_server/tcp_ipc_server_main.c
|
||
|
*
|
||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||
|
* contributor license agreements. See the NOTICE file distributed with
|
||
|
* this work for additional information regarding copyright ownership. The
|
||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||
|
* "License"); you may not use this file except in compliance with the
|
||
|
* License. You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||
|
* License for the specific language governing permissions and limitations
|
||
|
* under the License.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
/* This program consists of a server socket & custom messages to establish
|
||
|
* IPC for multiple applications (clients) and one process that controls
|
||
|
* LoRaWAN connectivity (server). Both client and server work on local
|
||
|
* network.
|
||
|
* For more details about client side, see client-tcp example.
|
||
|
*
|
||
|
* IMPORTANT NOTE:
|
||
|
* In order to test client_tcp & server_tcp together, there are two
|
||
|
* ways to proceed:
|
||
|
* 1) Init server manually (command: SERVER &), and after successfull
|
||
|
* server init, also init client manually (CLIENT 127.0.0.1)
|
||
|
* 2) init server automatically after boot using NuttShell start up scripts.
|
||
|
*/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Included Files
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <string.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
#include <pthread.h>
|
||
|
|
||
|
#include "protocol.h"
|
||
|
#include "lorawan/uart_lorawan_layer.h"
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Pre-processor Definitions
|
||
|
****************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Private Types
|
||
|
****************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Private Function Prototypes
|
||
|
****************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Private Data
|
||
|
****************************************************************************/
|
||
|
|
||
|
static int socket_clients_counter;
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Public Data
|
||
|
****************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Private Functions
|
||
|
****************************************************************************/
|
||
|
|
||
|
static void *thread_socket_client(void *arg);
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Public Functions
|
||
|
****************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Definitions
|
||
|
****************************************************************************/
|
||
|
|
||
|
#define SOCKET_PORT 5000
|
||
|
#define TX_BUFFER_SIZE 200
|
||
|
#define RX_BUFFER_SIZE 150
|
||
|
#define TCP_NO_FLAGS_WHEN_SENDING_DATA 0
|
||
|
#define IP_SERVER "127.0.0.1"
|
||
|
#define MAX_PENDING_SOCKET_CONNECTIONS 20
|
||
|
#define TIME_TO_CHECK_FOR_NEW_CLIENTS 500000
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: thread_socket_client
|
||
|
* Description: socket client thread. Each sonnected cleint socket will
|
||
|
* instantiate a thread, which handles all data traffic between
|
||
|
* this client and server.
|
||
|
* Parameters: thread arguments (in this case, file descriptor of client
|
||
|
* socket)
|
||
|
* Return: nothing
|
||
|
****************************************************************************/
|
||
|
|
||
|
static void *thread_socket_client(void *arg)
|
||
|
{
|
||
|
int socket_client_fd = *((int *)arg);
|
||
|
char tx_buffer[TX_BUFFER_SIZE];
|
||
|
unsigned char rx_buffer[RX_BUFFER_SIZE];
|
||
|
int bytes_read_from_server = 0;
|
||
|
int ret_send = 0;
|
||
|
protocolo_ipc tprotocol;
|
||
|
|
||
|
memset(tx_buffer, 0x00, sizeof(tx_buffer));
|
||
|
memset(rx_buffer, 0x00, sizeof(rx_buffer));
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
bytes_read_from_server = read(socket_client_fd,
|
||
|
rx_buffer,
|
||
|
RX_BUFFER_SIZE);
|
||
|
|
||
|
if (bytes_read_from_server == 0)
|
||
|
{
|
||
|
/* Socket disconnection has been detected.
|
||
|
* This thread will be terminated.
|
||
|
*/
|
||
|
|
||
|
printf("\n\rDisconnection has been detected.\n\r");
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Client request received! Comm. with client...\n");
|
||
|
send_msg_to_lpwan (rx_buffer, &tprotocol);
|
||
|
if (tprotocol.msg_size >= 0)
|
||
|
{
|
||
|
memcpy(tx_buffer,
|
||
|
(unsigned char *)&tprotocol,
|
||
|
sizeof(protocolo_ipc));
|
||
|
ret_send = send(socket_client_fd,
|
||
|
tx_buffer,
|
||
|
sizeof(protocolo_ipc),
|
||
|
TCP_NO_FLAGS_WHEN_SENDING_DATA);
|
||
|
|
||
|
if (ret_send > 0)
|
||
|
{
|
||
|
printf("\r\nSucess: %d bytes sent to client\r\n",
|
||
|
ret_send);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("\r\nError: fail to send %d bytes to client\r\n",
|
||
|
strlen(tx_buffer));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("ERROR: invalid message size (<0)\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Terminate this thread */
|
||
|
|
||
|
close(socket_client_fd);
|
||
|
socket_clients_counter--;
|
||
|
pthread_exit(NULL);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Server_tcp_main
|
||
|
****************************************************************************/
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
int socket_server_fd = 0;
|
||
|
int new_socket_client_fd = 0;
|
||
|
int ret_bind = 0;
|
||
|
struct sockaddr_in server_add;
|
||
|
struct sockaddr_storage server_storage;
|
||
|
socklen_t addr_size;
|
||
|
pthread_t tid[MAX_PENDING_SOCKET_CONNECTIONS];
|
||
|
config_lorawan_radioenge_t lora_config;
|
||
|
|
||
|
socket_clients_counter = 0;
|
||
|
|
||
|
/* Configuring LoRaWAN credentials */
|
||
|
|
||
|
snprintf(lora_config.application_session_key, APP_SESSION_KEY_SIZE,
|
||
|
"00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00");
|
||
|
snprintf(lora_config.network_session_key, NW_SESSION_KEY_SIZE,
|
||
|
"00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00");
|
||
|
snprintf(lora_config.application_eui, APP_EUI_SIZE,
|
||
|
"00:00:00:00:00:00:00:00");
|
||
|
snprintf(lora_config.device_address, DEVICE_ADDRESS_SIZE,
|
||
|
"00:00:00:00");
|
||
|
snprintf(lora_config.channel_mask, CHANNEL_MASK_SIZE,
|
||
|
"00FF:0000:0000:0000:0000:0000");
|
||
|
lorawan_radioenge_init(lora_config);
|
||
|
|
||
|
/* Create socket (server) */
|
||
|
|
||
|
socket_server_fd = socket(PF_INET, SOCK_STREAM, 0);
|
||
|
if (socket_server_fd == 0)
|
||
|
{
|
||
|
perror("Failed to create server socket");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
/* Fill addr structure and do socket bind operation */
|
||
|
|
||
|
server_add.sin_family = AF_INET;
|
||
|
server_add.sin_port = htons(SOCKET_PORT);
|
||
|
server_add.sin_addr.s_addr = inet_addr(IP_SERVER);
|
||
|
memset(server_add.sin_zero, '\0', sizeof server_add.sin_zero);
|
||
|
|
||
|
ret_bind = bind(socket_server_fd, (struct sockaddr *)&server_add,
|
||
|
sizeof(server_add));
|
||
|
if (ret_bind < 0)
|
||
|
{
|
||
|
perror("Failed to do socket bind operation");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
/* Initiate listening process for client sockets connection requests.
|
||
|
* The maximum number client sockets pending connection is
|
||
|
* defined by MAX_PENDING_SOCKET_CONNECTIONS
|
||
|
*/
|
||
|
|
||
|
if (listen(socket_server_fd, MAX_PENDING_SOCKET_CONNECTIONS) == 0)
|
||
|
{
|
||
|
printf("Listening for clients connections...\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
perror("Failed to listen for clients connections");
|
||
|
}
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
/* Wait for a new client socket connection */
|
||
|
|
||
|
addr_size = sizeof server_storage;
|
||
|
new_socket_client_fd = accept(socket_server_fd,
|
||
|
(struct sockaddr *)&server_storage,
|
||
|
&addr_size);
|
||
|
|
||
|
if (new_socket_client_fd < 0)
|
||
|
{
|
||
|
perror("Failed to accept new client socket connection");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
/* For each connected client socket, a new client thread
|
||
|
* is instantiated.
|
||
|
*/
|
||
|
|
||
|
if (pthread_create(&tid[socket_clients_counter++], NULL,
|
||
|
thread_socket_client, &new_socket_client_fd) != 0)
|
||
|
{
|
||
|
perror("Failed to instantiate a thread for new client socket\n");
|
||
|
}
|
||
|
|
||
|
if (socket_clients_counter <= MAX_PENDING_SOCKET_CONNECTIONS)
|
||
|
{
|
||
|
pthread_join(tid[socket_clients_counter++], NULL);
|
||
|
socket_clients_counter++;
|
||
|
}
|
||
|
|
||
|
usleep(TIME_TO_CHECK_FOR_NEW_CLIENTS);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|