UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
upnpdebug.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 *
3 * Copyright (c) 2000-2003 Intel Corporation
4 * All rights reserved.
5 * Copyright (C) 2021+ GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
6 * Redistribution only with this Copyright remark. Last modified: 2025-05-06
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 * - Neither name of Intel Corporation nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 ******************************************************************************/
33// Last compare with pupnp original source file on 2023-08-19, ver 1.14.17
38#define UPNP_DEBUG_C
39#include <config.hpp>
40#include <upnpdebug.hpp>
41
42#include <UPnPsdk/synclog.hpp>
43
44#include <umock/pthread.hpp>
45#include <umock/stdio.hpp>
46
48#include <cstdarg>
49#include <cstring>
51
52namespace {
53
55pthread_mutex_t debug_mutex;
56
57} // namespace
58
59
62
64static FILE* filed;
65
67static int setlogwascalled;
69static int initwascalled;
71static char* fileName;
72
73/* This is called from UpnpInit2(). So the user must call UpnpSetLogFileNames()
74 * before. This can be called again, for example to rotate the log
75 * file, and we try to avoid multiple calls to the mutex init, with a
76 * risk of race, probably not a problem, and not worth fixing. */
78 TRACE("Executing UpnpInitLog()")
79 if (!initwascalled) {
80 umock::pthread_h.pthread_mutex_init(&debug_mutex, nullptr);
81 initwascalled = 1;
82 }
83 /* If the user did not ask for logging do nothing */
84 if (setlogwascalled == 0) {
85 return UPNP_E_SUCCESS;
86 }
87
88 if (filed != nullptr && filed != stderr) {
89 umock::stdio_h.fclose(filed);
90 filed = nullptr;
91 }
92
93 if (fileName) {
94 filed = umock::stdio_h.fopen(fileName, "a");
95 if (filed == nullptr) {
96 fprintf(stderr,
97 "UPnPlib Error: failed to open filename \"%s\": %s. "
98 "Fallback to stderr.\n",
99 fileName, std::strerror(errno));
100 }
101 }
102
103 // If not set, always set to stderr, also as fallback for a wrong fileName.
104 if (filed == nullptr)
105 filed = stderr;
106
107 return UPNP_E_SUCCESS;
108}
109
111 TRACE("Executing UpnpSetLogLevel()")
112 g_log_level = log_level;
113 setlogwascalled = 1;
114}
115
117 TRACE("Executing UpnpCloseLog()")
118
119 /* Calling lock() assumes that someone called UpnpInitLog(), but
120 * this is reasonable as it is called from UpnpInit2(). We risk a
121 * crash if we do this without a lock.*/
122 if (initwascalled)
123 umock::pthread_h.pthread_mutex_lock(&debug_mutex);
124
125 if (filed != nullptr && filed != stderr) {
126 umock::stdio_h.fclose(filed);
127 }
128 filed = nullptr;
129 setlogwascalled = 0;
130 int init_called = initwascalled;
131 initwascalled = 0;
132 if (init_called) {
133 umock::pthread_h.pthread_mutex_unlock(&debug_mutex);
134 umock::pthread_h.pthread_mutex_destroy(&debug_mutex);
135 }
136}
137
138void UpnpSetLogFileNames(const char* newFileName,
139 [[maybe_unused]] const char* ignored) {
140 TRACE("Executing UpnpSetLogFileNames()")
141
142 if (fileName) {
143 free(fileName);
144 fileName = nullptr;
145 }
146 if (newFileName && *newFileName != '\0') {
147 fileName = strdup(newFileName);
148 }
149 setlogwascalled = 1;
150}
151
153static int DebugAtThisLevel(Upnp_LogLevel DLevel, Dbg_Module Module) {
154 return (DLevel <= g_log_level) &&
155 (DEBUG_ALL || (Module == SSDP && DEBUG_SSDP) ||
156 (Module == SOAP && DEBUG_SOAP) || (Module == GENA && DEBUG_GENA) ||
157 (Module == TPOOL && DEBUG_TPOOL) ||
158 (Module == MSERV && DEBUG_MSERV) || (Module == DOM && DEBUG_DOM) ||
159 (Module == HTTP && DEBUG_HTTP));
160}
161
163static void UpnpDisplayFileAndLine(FILE* a_fp, const char* DbgFileName,
164 int DbgLineNo, Upnp_LogLevel DLevel,
165 Dbg_Module Module) {
166 char timebuf[26];
167 time_t now = time(NULL);
168 const char* smod;
169#if 0
170 char *slev;
171 /* Code kept around in case, but I think it's actually more convenient
172 to display a numeric level */
173 switch (DLevel) {
174 case UPNP_CRITICAL: slev="CRI";break;
175 case UPNP_ERROR: slev="ERR";break;
176 case UPNP_INFO: slev="INF";break;
177 case UPNP_ALL: slev="ALL";break;
178 default: slev="UNK";break;
179 }
180#else
181 char slev[25];
182 snprintf(slev, 25, "%d", DLevel);
183#endif
184
185 switch (Module) {
186 case SSDP:
187 smod = "SSDP";
188 break;
189 case SOAP:
190 smod = "SOAP";
191 break;
192 case GENA:
193 smod = "GENA";
194 break;
195 case TPOOL:
196 smod = "TPOL";
197 break;
198 case MSERV:
199 smod = "MSER";
200 break;
201 case DOM:
202 smod = "DOM_";
203 break;
204 case API:
205 smod = "API_";
206 break;
207 case HTTP:
208 smod = "HTTP";
209 break;
210 default:
211 smod = "UNKN";
212 break;
213 }
214
215#ifdef _WIN32
216 struct tm timeinfo = {.tm_sec = 0,
217 .tm_min = 0,
218 .tm_hour = 0,
219 .tm_mday = 0,
220 .tm_mon = 0,
221 .tm_year = 0,
222 .tm_wday = 0,
223 .tm_yday = 0,
224 .tm_isdst = 0};
225 localtime_s(&timeinfo, &now);
226 strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", &timeinfo);
227#else
228 struct tm* timeinfo;
229 timeinfo = localtime(&now);
230 strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", timeinfo);
231#endif
232
233 fprintf(a_fp, "%s UPNP-%s-%s: Thread:0x%llX [%s:%d]: ", timebuf, smod, slev,
234#ifdef __PTW32_DLLPORT
235 *(unsigned long long int*)pthread_self().p
236#else
237 (unsigned long long int)pthread_self()
238#endif
239 ,
240 DbgFileName, DbgLineNo);
241}
242
245 const char* DbgFileName, int DbgLineNo, const char* FmtStr,
246 ...) {
247 /*fprintf(stderr, "UpnpPrintf: filed %p level %d glev %d mod %d DEBUG_ALL
248 %d\n", filed, DLevel, g_log_level, Module, DEBUG_ALL);*/
249 va_list ArgList;
250
251 if (!initwascalled) {
252 return;
253 }
254
255 if (!DebugAtThisLevel(DLevel, Module))
256 return;
257 umock::pthread_h.pthread_mutex_lock(&debug_mutex);
258 if (filed == nullptr) {
259 umock::pthread_h.pthread_mutex_unlock(&debug_mutex);
260 return;
261 }
262
263 va_start(ArgList, FmtStr);
264 if (DbgFileName) {
265 // flush stdout to have a sequencial output with stderr on screen.
266 fflush(stdout); // Don't mock this because we use it for debuging.
267 UpnpDisplayFileAndLine(filed, DbgFileName + CMAKE_SOURCE_PATH_LENGTH,
268 DbgLineNo, DLevel, Module);
269 vfprintf(filed, FmtStr, ArgList);
270 if (filed != nullptr && filed != stderr)
271 fflush(filed); // Don't mock this because we use it for debuging.
272 }
273 va_end(ArgList);
274 umock::pthread_h.pthread_mutex_unlock(&debug_mutex);
275}
276
277/* No locking here, the app should be careful about not calling
278 closelog from a separate thread... */
280 if (!DebugAtThisLevel(DLevel, Module)) {
281 return nullptr;
282 } else {
283 return filed;
284 }
285}
Main program configuration file.
#define DEBUG_ALL
Debug feature.
Definition config.hpp:279
#define DEBUG_MSERV
Debug feature.
Definition config.hpp:284
#define DEBUG_GENA
Debug feature.
Definition config.hpp:282
#define DEBUG_TPOOL
Debug feature.
Definition config.hpp:283
#define DEBUG_SOAP
Debug feature.
Definition config.hpp:281
#define DEBUG_SSDP
Debug feature.
Definition config.hpp:280
#define DEBUG_HTTP
Debug feature.
Definition config.hpp:286
#define DEBUG_DOM
Debug feature.
Definition config.hpp:285
#define UPNP_E_SUCCESS
The operation completed successfully.
Definition messages.hpp:27
Define macro for synced logging to the console for detailed info and debug.
void UpnpSetLogLevel(Upnp_LogLevel log_level)
Set the log level (see Upnp_LogLevel).
static Upnp_LogLevel g_log_level
Definition upnpdebug.cpp:61
static char * fileName
Definition upnpdebug.cpp:71
static void UpnpDisplayFileAndLine(FILE *a_fp, const char *DbgFileName, int DbgLineNo, Upnp_LogLevel DLevel, Dbg_Module Module)
Display File and Line.
void UpnpSetLogFileNames(const char *newFileName, const char *ignored)
Set the name for the log file. There used to be 2 separate files. The second parameter has been kept ...
FILE * UpnpGetDebugFile(Upnp_LogLevel DLevel, Dbg_Module Module)
Check if the module is turned on for debug and returns the file descriptor corresponding to the debug...
static int initwascalled
Definition upnpdebug.cpp:69
int UpnpInitLog()
Initialize the log files.
Definition upnpdebug.cpp:77
static int DebugAtThisLevel(Upnp_LogLevel DLevel, Dbg_Module Module)
Check Debug level.
static int setlogwascalled
Definition upnpdebug.cpp:67
void UpnpCloseLog()
Closes the log files.
static FILE * filed
Definition upnpdebug.cpp:64
void UpnpPrintf(Upnp_LogLevel DLevel, Dbg_Module Module, const char *DbgFileName, int DbgLineNo, const char *FmtStr,...)
Prints the debug statement.
Manage Debug messages with levels "critical" to "all".
enum Upnp_Module Dbg_Module
Only debug messages from this program module.
#define UPNP_DEFAULT_LOG_LEVEL
enum Upnp_LogLevel_e Upnp_LogLevel
Upnp_LogLevel.