Go to the documentation of this file.
1 /**
2  * @file syslog_client.c
3  * @brief Syslog client
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The Syslog protocol is used to convey event notification messages. It
30  * provides a message format that allows vendor-specific extensions to be
31  * provided in a structured way. Refer to RFC 3164 for more details
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.4.4
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL SYSLOG_TRACE_LEVEL
39 
40 //Dependencies
41 #include <stdarg.h>
42 #include "syslog/syslog_client.h"
44 #include "debug.h"
45 
46 //Check TCP/IP stack configuration
47 #if (SYSLOG_CLIENT_SUPPORT == ENABLED)
48 
49 
50 /**
51  * @brief Syslog client initialization
52  * @param[in] context Pointer to the Syslog client context
53  * @return Error code
54  **/
55 
57 {
58  //Make sure the Syslog client context is valid
59  if(context == NULL)
61 
62  //Debug message
63  TRACE_INFO("Initializing Syslog client...\r\n");
64 
65  //Initialize context
66  osMemset(context, 0, sizeof(SyslogClientContext));
67  //Use default interface
68  context->interface = netGetDefaultInterface();
69 
70  //Create a mutex to prevent simultaneous access to the context
71  if(!osCreateMutex(&context->mutex))
73 
74  //Successful initialization
75  return NO_ERROR;
76 }
77 
78 
79 /**
80  * @brief Bind the Syslog client to a particular network interface
81  * @param[in] context Pointer to the Syslog client context
82  * @param[in] interface Network interface to be used
83  * @return Error code
84  **/
85 
87  NetInterface *interface)
88 {
89  //Make sure the Syslog client context is valid
90  if(context == NULL)
92 
93  //Explicitly associate the Syslog client with the specified interface
94  context->interface = interface;
95 
96  //Successful processing
97  return NO_ERROR;
98 }
99 
100 
101 /**
102  * @brief Specify the address of the Syslog server
103  * @param[in] context Pointer to the Syslog client context
104  * @param[in] serverIpAddr IP address of the Syslog server to connect to
105  * @param[in] serverPort UDP port number
106  * @return Error code
107  **/
108 
110  const IpAddr *serverIpAddr, uint16_t serverPort)
111 {
112  error_t error;
113 
114  //Check parameters
115  if(context == NULL || serverIpAddr == NULL)
117 
118  //Start of exception handling block
119  do
120  {
121  //Open a UDP socket
123  //Failed to open socket?
124  if(context->socket == NULL)
125  {
126  //Report an error
127  error = ERROR_OPEN_FAILED;
128  break;
129  }
130 
131  //Associate the socket with the relevant interface
132  error = socketBindToInterface(context->socket, context->interface);
133  //Any error to report?
134  if(error)
135  break;
136 
137  //Connect the socket to the remote Syslog server
138  error = socketConnect(context->socket, serverIpAddr, serverPort);
139  //Any error to report?
140  if(error)
141  break;
142 
143  //End of exception handling block
144  } while(0);
145 
146  //Any error to report?
147  if(error)
148  {
149  //Clean up side effects
150  socketClose(context->socket);
151  context->socket = NULL;
152  }
153 
154  //Return status code
155  return error;
156 }
157 
158 
159 /**
160  * @brief Send Syslog message
161  * @param[in] context Pointer to the Syslog client context
162  * @param[in] facility Facility value
163  * @param[in] severity Severity value
164  * @param[in] message NULL-terminated string that holds the message
165  * @return Error code
166  **/
167 
169  uint_t severity, const char_t *message)
170 {
171  error_t error;
172  size_t n;
173  size_t messageLen;
175  time_t time;
176 
177  //Check parameters
178  if(context == NULL || message == NULL)
180 
181  //Make sure the UDP socket is valid
182  if(context->socket == NULL)
183  return ERROR_NOT_CONNECTED;
184 
185  //Acquire exclusive access to the Syslog client context
186  osAcquireMutex(&context->mutex);
187 
188  //The Priority value is calculated by first multiplying the Facility
189  //number by 8 and then adding the numerical value of the Severity
190  priority = (facility * 8) + severity;
191 
192  //Format the PRI part of the Syslog packet
193  n = osSprintf(context->buffer, "<%u> ", priority);
194 
195  //Retrieve current time
197  //Format TIMESTAMP field
198  n += syslogClientFormatTimestamp(time, context->buffer + n);
199 
200  //Format HOSTNAME field
201  n += osSprintf(context->buffer + n, " %s ", context->interface->hostname);
202 
203  //Retrieve the length of the message
204  messageLen = osStrlen(message);
205  //The MSG part will fill the remainder of the syslog message
206  messageLen = MIN(messageLen, SYSLOG_CLIENT_BUFFER_SIZE - 1 - n);
207 
208  //Format the MSG part of the Syslog packet
209  osStrncpy(context->buffer + n, message, messageLen);
210  //Total length of the Syslog packet
211  n += messageLen;
212 
213  //Properly terminate the string with a NULL character
214  context->buffer[n] = '\0';
215 
216  //Debug message
217  TRACE_DEBUG("Sending Syslog message (%" PRIuSIZE " bytes)...\r\n", n);
218  TRACE_DEBUG(" %s\r\n", context->buffer);
219 
220  //Send Syslog packet
221  error = socketSend(context->socket, context->buffer, n, NULL, 0);
222 
223  //Release exclusive access to the Syslog client context
224  osReleaseMutex(&context->mutex);
225 
226  //Return status code
227  return error;
228 }
229 
230 
231 /**
232  * @brief Format Syslog message
233  * @param[in] context Pointer to the Syslog client context
234  * @param[in] facility Facility value
235  * @param[in] severity Severity value
236  * @param[in] format NULL-terminated string that that contains a format string
237  * @param[in] ... Optional arguments
238  * @return Error code
239  **/
240 
242  uint_t severity, const char_t *format, ...)
243 {
244  error_t error;
245  size_t n;
246  size_t maxMessageLen;
248  time_t time;
249  va_list args;
250 
251  //Check parameters
252  if(context == NULL || format == NULL)
254 
255  //Make sure the UDP socket is valid
256  if(context->socket == NULL)
257  return ERROR_NOT_CONNECTED;
258 
259  //Acquire exclusive access to the Syslog client context
260  osAcquireMutex(&context->mutex);
261 
262  //The Priority value is calculated by first multiplying the Facility
263  //number by 8 and then adding the numerical value of the Severity
264  priority = (facility * 8) + severity;
265 
266  //Format the PRI part of the Syslog packet
267  n = osSprintf(context->buffer, "<%u> ", priority);
268 
269  //Retrieve current time
271  //Format TIMESTAMP field
272  n += syslogClientFormatTimestamp(time, context->buffer + n);
273 
274  //Format HOSTNAME field
275  n += osSprintf(context->buffer + n, " %s ", context->interface->hostname);
276 
277  //The MSG part will fill the remainder of the syslog message
278  maxMessageLen = SYSLOG_CLIENT_BUFFER_SIZE - 1 - n;
279 
280  //Initialize processing of a varying-length argument list
281  va_start(args, format);
282  //Format the MSG part of the Syslog packet
283  n += osVsnprintf(context->buffer + n, maxMessageLen, format, args);
284  //End varying-length argument list processing
285  va_end(args);
286 
287  //Debug message
288  TRACE_DEBUG("Sending Syslog message (%" PRIuSIZE " bytes)...\r\n", n);
289  TRACE_DEBUG(" %s\r\n", context->buffer);
290 
291  //Send Syslog packet
292  error = socketSend(context->socket, context->buffer, n, NULL, 0);
293 
294  //Release exclusive access to the Syslog client context
295  osReleaseMutex(&context->mutex);
296 
297  //Return status code
298  return error;
299 }
300 
301 
302 /**
303  * @brief Close the connection with the Syslog server
304  * @param[in] context Pointer to the Syslog client context
305  * @return Error code
306  **/
307 
309 {
310  //Make sure the Syslog client context is valid
311  if(context == NULL)
313 
314  //Close UDP socket
315  if(context->socket != NULL)
316  {
317  socketClose(context->socket);
318  context->socket = NULL;
319  }
320 
321  //Successful processing
322  return NO_ERROR;
323 }
324 
325 
326 /**
327  * @brief Release Syslog client context
328  * @param[in] context Pointer to the Syslog client context
329  **/
330 
332 {
333  //Make sure the Syslog client context is valid
334  if(context != NULL)
335  {
336  //Close UDP socket
337  if(context->socket != NULL)
338  {
339  socketClose(context->socket);
340  }
341 
342  //Release previously allocated resources
343  osDeleteMutex(&context->mutex);
344 
345  //Clear Syslog client context
346  osMemset(context, 0, sizeof(SyslogClientContext));
347  }
348 }
349 
350 #endif
error_t socketSend(Socket *socket, const void *data, size_t length, size_t *written, uint_t flags)
Send data to a connected socket.
Definition: socket.c:1486
@ SOCKET_IP_PROTO_UDP
Definition: socket.h:108
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
IP network address.
Definition: ip.h:90
error_t syslogClientInit(SyslogClientContext *context)
Syslog client initialization.
Definition: syslog_client.c:56
char_t buffer[SYSLOG_CLIENT_BUFFER_SIZE]
Internal buffer.
uint8_t message[]
Definition: chap.h:154
Syslog client.
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2062
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ SOCKET_TYPE_DGRAM
Definition: socket.h:93
void syslogClientDeinit(SyslogClientContext *context)
Release Syslog client context.
#define osStrlen(s)
Definition: os_port.h:165
size_t syslogClientFormatTimestamp(time_t time, char_t *buffer)
Format timestamp.
error_t syslogClientClose(SyslogClientContext *context)
Close the connection with the Syslog server.
#define SYSLOG_CLIENT_BUFFER_SIZE
Definition: syslog_client.h:46
error_t syslogClientSendMessage(SyslogClientContext *context, uint_t facility, uint_t severity, const char_t *message)
Send Syslog message.
@ ERROR_OPEN_FAILED
Definition: error.h:75
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:43
#define osSprintf(dest,...)
Definition: os_port.h:231
#define osVsnprintf(dest, size, format, ap)
Definition: os_port.h:243
Syslog client context.
#define NetInterface
Definition: net.h:36
NetInterface * netGetDefaultInterface(void)
Get default network interface.
Definition: net.c:467
error_t syslogClientFormatMessage(SyslogClientContext *context, uint_t facility, uint_t severity, const char_t *format,...)
Format Syslog message.
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1349
error_t syslogClientConnect(SyslogClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort)
Specify the address of the Syslog server.
#define TRACE_INFO(...)
Definition: debug.h:95
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:125
#define MIN(a, b)
Definition: os_port.h:63
#define socketBindToInterface
Definition: net_legacy.h:193
#define TRACE_DEBUG(...)
Definition: debug.h:107
char char_t
Definition: compiler_port.h:48
uint32_t time
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
@ ERROR_NOT_CONNECTED
Definition: error.h:80
uint8_t n
Socket * socket
Underlying UDP socket.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
error_t syslogClientBindToInterface(SyslogClientContext *context, NetInterface *interface)
Bind the Syslog client to a particular network interface.
Definition: syslog_client.c:86
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
#define osStrncpy(s1, s2, length)
Definition: os_port.h:213
NetInterface * interface
Underlying network interface.
OsMutex mutex
Mutex preventing simultaneous access to the context.
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
uint16_t priority
Definition: dns_common.h:265
__weak_func time_t getCurrentUnixTime(void)
Get current time.
Definition: date_time.c:180
Helper functions for Syslog client.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.