syslog_client.c
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-2026 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.6.0
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  //Clear Syslog client context
66  osMemset(context, 0, sizeof(SyslogClientContext));
67 
68  //Attach TCP/IP stack context
69  context->netContext = netGetDefaultContext();
70  //Use default interface
71  context->interface = netGetDefaultInterface(context->netContext);
72 
73  //Create a mutex to prevent simultaneous access to the context
74  if(!osCreateMutex(&context->mutex))
76 
77  //Successful initialization
78  return NO_ERROR;
79 }
80 
81 
82 /**
83  * @brief Bind the Syslog client to a particular network interface
84  * @param[in] context Pointer to the Syslog client context
85  * @param[in] interface Network interface to be used
86  * @return Error code
87  **/
88 
90  NetInterface *interface)
91 {
92  //Make sure the Syslog client context is valid
93  if(context == NULL)
95 
96  //Explicitly associate the Syslog client with the specified interface
97  context->interface = interface;
98 
99  //Successful processing
100  return NO_ERROR;
101 }
102 
103 
104 /**
105  * @brief Specify the address of the Syslog server
106  * @param[in] context Pointer to the Syslog client context
107  * @param[in] serverIpAddr IP address of the Syslog server to connect to
108  * @param[in] serverPort UDP port number
109  * @return Error code
110  **/
111 
113  const IpAddr *serverIpAddr, uint16_t serverPort)
114 {
115  error_t error;
116 
117  //Check parameters
118  if(context == NULL || serverIpAddr == NULL)
120 
121  //Start of exception handling block
122  do
123  {
124  //Open a UDP socket
125  context->socket = socketOpenEx(context->netContext, SOCKET_TYPE_DGRAM,
127  //Failed to open socket?
128  if(context->socket == NULL)
129  {
130  //Report an error
131  error = ERROR_OPEN_FAILED;
132  break;
133  }
134 
135  //Associate the socket with the relevant interface
136  error = socketBindToInterface(context->socket, context->interface);
137  //Any error to report?
138  if(error)
139  break;
140 
141  //Connect the socket to the remote Syslog server
142  error = socketConnect(context->socket, serverIpAddr, serverPort);
143  //Any error to report?
144  if(error)
145  break;
146 
147  //End of exception handling block
148  } while(0);
149 
150  //Any error to report?
151  if(error)
152  {
153  //Clean up side effects
154  socketClose(context->socket);
155  context->socket = NULL;
156  }
157 
158  //Return status code
159  return error;
160 }
161 
162 
163 /**
164  * @brief Send Syslog message
165  * @param[in] context Pointer to the Syslog client context
166  * @param[in] facility Facility value
167  * @param[in] severity Severity value
168  * @param[in] message NULL-terminated string that holds the message
169  * @return Error code
170  **/
171 
173  uint_t severity, const char_t *message)
174 {
175  error_t error;
176  size_t n;
177  size_t messageLen;
179  time_t time;
180 
181  //Check parameters
182  if(context == NULL || message == NULL)
184 
185  //Make sure the UDP socket is valid
186  if(context->socket == NULL)
187  return ERROR_NOT_CONNECTED;
188 
189  //Acquire exclusive access to the Syslog client context
190  osAcquireMutex(&context->mutex);
191 
192  //The Priority value is calculated by first multiplying the Facility
193  //number by 8 and then adding the numerical value of the Severity
194  priority = (facility * 8) + severity;
195 
196  //Format the PRI part of the Syslog packet
197  n = osSprintf(context->buffer, "<%u> ", priority);
198 
199  //Retrieve current time
201  //Format TIMESTAMP field
202  n += syslogClientFormatTimestamp(time, context->buffer + n);
203 
204  //Format HOSTNAME field
205  n += osSprintf(context->buffer + n, " %s ", context->interface->hostname);
206 
207  //Retrieve the length of the message
208  messageLen = osStrlen(message);
209  //The MSG part will fill the remainder of the syslog message
210  messageLen = MIN(messageLen, SYSLOG_CLIENT_BUFFER_SIZE - 1 - n);
211 
212  //Format the MSG part of the Syslog packet
213  osStrncpy(context->buffer + n, message, messageLen);
214  //Total length of the Syslog packet
215  n += messageLen;
216 
217  //Properly terminate the string with a NULL character
218  context->buffer[n] = '\0';
219 
220  //Debug message
221  TRACE_DEBUG("Sending Syslog message (%" PRIuSIZE " bytes)...\r\n", n);
222  TRACE_DEBUG(" %s\r\n", context->buffer);
223 
224  //Send Syslog packet
225  error = socketSend(context->socket, context->buffer, n, NULL, 0);
226 
227  //Release exclusive access to the Syslog client context
228  osReleaseMutex(&context->mutex);
229 
230  //Return status code
231  return error;
232 }
233 
234 
235 /**
236  * @brief Format Syslog message
237  * @param[in] context Pointer to the Syslog client context
238  * @param[in] facility Facility value
239  * @param[in] severity Severity value
240  * @param[in] format NULL-terminated string that that contains a format string
241  * @param[in] ... Optional arguments
242  * @return Error code
243  **/
244 
246  uint_t severity, const char_t *format, ...)
247 {
248  error_t error;
249  size_t n;
250  size_t maxMessageLen;
252  time_t time;
253  va_list args;
254 
255  //Check parameters
256  if(context == NULL || format == NULL)
258 
259  //Make sure the UDP socket is valid
260  if(context->socket == NULL)
261  return ERROR_NOT_CONNECTED;
262 
263  //Acquire exclusive access to the Syslog client context
264  osAcquireMutex(&context->mutex);
265 
266  //The Priority value is calculated by first multiplying the Facility
267  //number by 8 and then adding the numerical value of the Severity
268  priority = (facility * 8) + severity;
269 
270  //Format the PRI part of the Syslog packet
271  n = osSprintf(context->buffer, "<%u> ", priority);
272 
273  //Retrieve current time
275  //Format TIMESTAMP field
276  n += syslogClientFormatTimestamp(time, context->buffer + n);
277 
278  //Format HOSTNAME field
279  n += osSprintf(context->buffer + n, " %s ", context->interface->hostname);
280 
281  //The MSG part will fill the remainder of the syslog message
282  maxMessageLen = SYSLOG_CLIENT_BUFFER_SIZE - 1 - n;
283 
284  //Initialize processing of a varying-length argument list
285  va_start(args, format);
286  //Format the MSG part of the Syslog packet
287  n += osVsnprintf(context->buffer + n, maxMessageLen, format, args);
288  //End varying-length argument list processing
289  va_end(args);
290 
291  //Debug message
292  TRACE_DEBUG("Sending Syslog message (%" PRIuSIZE " bytes)...\r\n", n);
293  TRACE_DEBUG(" %s\r\n", context->buffer);
294 
295  //Send Syslog packet
296  error = socketSend(context->socket, context->buffer, n, NULL, 0);
297 
298  //Release exclusive access to the Syslog client context
299  osReleaseMutex(&context->mutex);
300 
301  //Return status code
302  return error;
303 }
304 
305 
306 /**
307  * @brief Close the connection with the Syslog server
308  * @param[in] context Pointer to the Syslog client context
309  * @return Error code
310  **/
311 
313 {
314  //Make sure the Syslog client context is valid
315  if(context == NULL)
317 
318  //Close UDP socket
319  if(context->socket != NULL)
320  {
321  socketClose(context->socket);
322  context->socket = NULL;
323  }
324 
325  //Successful processing
326  return NO_ERROR;
327 }
328 
329 
330 /**
331  * @brief Release Syslog client context
332  * @param[in] context Pointer to the Syslog client context
333  **/
334 
336 {
337  //Make sure the Syslog client context is valid
338  if(context != NULL)
339  {
340  //Close UDP socket
341  if(context->socket != NULL)
342  {
343  socketClose(context->socket);
344  }
345 
346  //Release previously allocated resources
347  osDeleteMutex(&context->mutex);
348 
349  //Clear Syslog client context
350  osMemset(context, 0, sizeof(SyslogClientContext));
351  }
352 }
353 
354 #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:1514
@ 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:2094
@ 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:168
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:234
#define osVsnprintf(dest, size, format, ap)
Definition: os_port.h:246
Syslog client context.
#define NetInterface
Definition: net.h:40
NetContext * netGetDefaultContext(void)
Get default TCP/IP stack context.
Definition: net.c:527
error_t syslogClientFormatMessage(SyslogClientContext *context, uint_t facility, uint_t severity, const char_t *format,...)
Format Syslog message.
NetInterface * netGetDefaultInterface(NetContext *context)
Get default network interface.
Definition: net.c:540
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1377
error_t syslogClientConnect(SyslogClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort)
Specify the address of the Syslog server.
#define TRACE_INFO(...)
Definition: debug.h:105
#define MIN(a, b)
Definition: os_port.h:63
#define socketBindToInterface
Definition: net_legacy.h:193
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
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:89
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Socket * socketOpenEx(NetContext *context, uint_t type, uint_t protocol)
Create a socket.
Definition: socket.c:146
#define osStrncpy(s1, s2, length)
Definition: os_port.h:216
NetInterface * interface
Underlying network interface.
OsMutex mutex
Mutex preventing simultaneous access to the context.
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
NetContext * netContext
TCP/IP stack context.
uint16_t priority
Definition: dns_common.h:268
__weak_func time_t getCurrentUnixTime(void)
Get current time.
Definition: date_time.c:186
Helper functions for Syslog client.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.