Repository navigation
Expand file tree
/
Copy pathtcp_server.c
More file actions
222 lines (189 loc) · 6.53 KB
/
Copy pathtcp_server.c
File metadata and controls
222 lines (189 loc) · 6.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
* =============================================================================
* File : tcp_server.c
* Author : Leandro Martins dos Santos
* Created on : 2025-02-27
* Last Update : 2025-11-04
* Version : 1.0
* Description : TCP server implementation for Power PMAC communication.
* Receives messages from a TCP client and writes values to Power PMAC shared memory.
*
* Dependencies:
* - gplib.h (Delta Tau Power PMAC library)
* - stdlib.h, errno.h, signal.h, string.h, netinet/in.h, sys/socket.h
*
* Compiler : Power PMAC IDE (Visual Studio-based) or GCC (Linux)
* Target : Power PMAC CPU (Linux/Xenomai RT kernel)
*
* License : Apache-2.0
*
* =============================================================================
*/
#include "tcp_server.h"
void InitSocket(char *host, int port) {
struct sockaddr_in serverAddr;
//------------------------------------------------
// Reguired uncontrolled program terminations
//-------------------------------------------------
signal(SIGTERM,kill_handler); // Process Termination (pkill)
signal(SIGINT,kill_handler); // Interrupt from keyboard (^C)
signal(SIGHUP,kill_handler); // Hangup of controlling window (Close of CMD window)
signal(SIGKILL,kill_handler); // Forced termination (ps -9)
signal(SIGABRT,kill_handler); // Abnormal termination (segmentation fault)
// Create the TCP socket
if ((serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
Die("Failed to create socket");
}
// Set socket options
int opt = 1;
if (setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
Die("Failed to set socket options");
}
// Construct the server sockaddr_in structure
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(port);
if (inet_pton(AF_INET, host, &serverAddr.sin_addr) <= 0) {
Die("Invalid address/ Address not supported");
}
// Bind the server socket
if (bind(serverSock, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) {
Die("Failed to bind the server socket");
}
// Listen on the server socket
if (listen(serverSock, MAXPENDING) < 0) {
Die("Failed to listen on server socket");
}
}
int AcceptClient() {
int clientSock;
struct sockaddr_in clientAddr;
socklen_t clientLen;
// Run until cancelled
while (1) {
clientLen = sizeof(clientAddr);
// Wait for client connection
if ((clientSock = accept(serverSock, (struct sockaddr *) &clientAddr, &clientLen)) < 0) {
Die("Failed to accept client connection");
}
else {
return clientSock;
}
}
}
int HandleClient(int clientSock, char * buffer, size_t data_size) {
static size_t bytes_received;
#ifndef SIMULATION_MODE
InitLibrary(); // Required for accessing Power PMAC library
#ifdef DEBUG
double exec_time = GetCPUClock();
#endif // DEBUG
#endif // SIMULATION_MODE
// Receive message from client
bytes_received = recv(clientSock, buffer, data_size*sizeof(double), 0);
if (bytes_received <= 0) {
if (bytes_received < 0) {
perror("recv");
}
return -1;
}
// Check for shutdown command
if (strncmp(buffer, SHUTDOWN_CMD, bytes_received) == 0) {
printf("Shutdown command received\n");
close(clientSock);
close(serverSock);
#ifndef SIMULATION_MODE
CloseLibrary();
#endif
exit(EXIT_SUCCESS);
return 1;
}
// Check if the received bytes match the expected size
if (bytes_received != data_size) {
printf("Warning: Expected %zd bytes, but received %zd bytes\n", data_size, bytes_received);
}
#ifdef DEBUG // Does this still make sense here?
printf("%f\n", GetCPUClock()-exec_time);
#endif
return 0;
}
void CloseSocket(int sock) {
int error = 0;
socklen_t len = sizeof(error);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) != 0 || error != 0) {
close(sock);
}
}
void Die(char *message) {
perror(message);
exit(EXIT_FAILURE);
}
void kill_handler(int sig) {
close(serverSock);
#ifndef SIMULATION_MODE
CloseLibrary();
#endif
exit(EXIT_SUCCESS);
}
void test_print_data(double *dest, size_t data_count) {
int i;
for (i = 0; i < data_count; i++) {
printf("%p: %3.4f \t| ", dest, *dest);
dest++;
}
printf("\n");
}
int main() {
#ifdef SIMULATION_MODE
pushm = (void *)malloc(sizeof(pushm)); // HACK
pshm = (void *)malloc(sizeof(pshm)); // HACK
#else
struct sched_param param;
int done = 0;
struct timespec sleeptime = {0};
sleeptime.tv_nsec = NANO_5MSEC; // #defines NANO_1MSEC, NANO_5MSEC & NANO_10MSEC are defined
#ifndef RUN_AS_RT_APP
//-----------------------------
// Runs as a NON RT Linux APP
//-----------------------------
param.__sched_priority = 0;
pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m);
#else
//---------------------------------------------------------------
// Runs as a RT Linux APP with the same scheduling policy as the
// Background script PLCs
// To run at a recommended lower priority use BACKGROUND_RT_PRIORITY - 10
// To run at a higher priority use BACKGROUND_RT_PRIORITY + 1
//---------------------------------------------------------------------
param.__sched_priority = BACKGROUND_RT_PRIORITY - 10;
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
#endif // RUN_AS_RT_APP
InitLibrary(); // Required for accessing Power PMAC library
#endif // SIMULATION_MODE
// global int serverSock due to kill_handler
char *host = "127.0.0.1";
int port = 8080;
size_t data_count = 7;
size_t data_size = data_count*sizeof(double);
int clientSock;
int socketStatus;
double *dest = (double *) malloc(data_size);
char buffer[BUFFSIZE];
InitSocket(host, port);
clientSock = AcceptClient();
do {
// TODO: Add busy-wait here until buffer is clear to be overwritten
socketStatus = HandleClient(clientSock, buffer, data_size);
memcpy(dest, buffer, data_size);
test_print_data(dest, data_count);
} while (socketStatus == 0);
CloseSocket(clientSock);
CloseSocket(serverSock);
#ifdef SIMULATION_MODE
free(pushm);
#else
CloseLibrary();
#endif
return 0;
}