Bug Summary

File:build-analysis/../src/clients/lib/xmmsclient/result.c
Warning:line 565, column 10
Use of memory after it is freed

Annotated Source Code

1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2017 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/types.h>
20#include <string.h>
21#include <ctype.h>
22
23#include <sys/types.h>
24
25#include <xmmsclient/xmmsclient.h>
26#include <xmmsclientpriv/xmmsclient.h>
27#include <xmmsclientpriv/xmmsclient_ipc.h>
28#include <xmmsc/xmmsc_idnumbers.h>
29#include <xmmsc/xmmsc_errorcodes.h>
30#include <xmmsc/xmmsc_stdint.h>
31#include <xmmsc/xmmsc_stdbool.h>
32#include <xmmscpriv/xmmsv_c2c.h>
33
34typedef enum {
35 XMMSC_RESULT_CALLBACK_DEFAULT,
36 XMMSC_RESULT_CALLBACK_RAW,
37 XMMSC_RESULT_CALLBACK_C2C
38} xmmsc_result_callback_type_t;
39
40typedef struct xmmsc_result_callback_St {
41 xmmsc_result_callback_type_t type;
42 xmmsc_result_notifier_t func;
43
44 void *user_data;
45 xmmsc_user_data_free_func_t free_func;
46} xmmsc_result_callback_t;
47
48static void xmmsc_result_restart (xmmsc_result_t *res);
49static void xmmsc_result_notifier_add (xmmsc_result_t *res, xmmsc_result_callback_t *cb);
50static void xmmsc_result_notifier_remove (xmmsc_result_t *res, x_list_t *node);
51static void xmmsc_result_notifier_delete (xmmsc_result_t *res, x_list_t *node);
52static void xmmsc_result_notifier_delete_all (xmmsc_result_t *res);
53
54static xmmsc_result_callback_t *xmmsc_result_callback_new_default (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f);
55static xmmsc_result_callback_t *xmmsc_result_callback_new_raw (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f);
56static xmmsc_result_callback_t *xmmsc_result_callback_new_c2c (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f);
57
58struct xmmsc_result_St {
59 xmmsc_connection_t *c;
60
61 /** refcounting */
62 int ref;
63
64 xmmsc_result_type_t type;
65
66 /** notifiers */
67 x_list_t *notifiers;
68
69 xmmsc_ipc_t *ipc;
70
71 bool_Bool parsed;
72 bool_Bool is_c2c;
73
74 uint32_t cookie;
75 uint32_t restart_signal;
76
77 xmmsv_t *data;
78
79 xmmsc_visualization_t *visc;
80};
81
82/**
83 * @defgroup Result Result
84 * @brief Result manipulation and error handling
85 * @ingroup XMMSClient
86 *
87 * Each command to the server will return a #xmmsc_result_t
88 * to the programmer. This object will be used to see the results
89 * off the call. It will handle errors and the results.
90 *
91 * results could be used in both sync and async fashions. Here
92 * is a sync example:
93 * @code
94 * xmmsc_result_t *res;
95 * xmmsv_t *val;
96 * uint32_t id;
97 * res = xmmsc_playback_get_current_id (connection);
98 * xmmsc_result_wait (res);
99 * if (!val = xmmsc_result_get_value (res)) {
100 * printf ("error: failed to retrieve value!");
101 * }
102 * if (xmmsv_is_error (val)) {
103 * printf ("error: %s", xmmsv_get_error (val));
104 * }
105 * xmmsv_get_uint (val, &id);
106 * xmmsc_result_unref (res);
107 * printf ("current id is: %d", id);
108 * @endcode
109 *
110 * an async example is a bit more complex...
111 * @code
112 * static void handler (xmmsv_t *val, void *userdata) {
113 * uint32_t id;
114 * if (xmmsv_is_error (val)) {
115 * printf ("error: %s", xmmsv_get_error (val));
116 * }
117 * xmmsv_get_uint (val, &id);
118 * printf ("current id is: %d", id);
119 * }
120 *
121 * int main () {
122 * // Connect blah blah ...
123 * xmmsc_result_t *res;
124 * res = xmmsc_playback_get_current_id (connection);
125 * xmmsc_result_notifier_set (res, handler);
126 * xmmsc_result_unref (res);
127 * }
128 * @endcode
129 * When the answer arrives handler will be called. with the resulting #xmmsv_t
130 * @{
131**/
132
133/**
134 * References the #xmmsc_result_t
135 *
136 * @param result the result to reference.
137 * @return result
138 */
139xmmsc_result_t *
140xmmsc_result_ref (xmmsc_result_t *res)
141{
142 x_return_val_if_fail (res, NULL)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 142); return (((void*)0)); }
;
143 res->ref++;
144
145 return res;
146}
147
148/**
149 * @todo Deallocate all types here
150 */
151static void
152xmmsc_result_free (xmmsc_result_t *res)
153{
154 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 154); return; }
;
155
156 /* Free memory! */
157 if (res->ipc) {
17
Assuming the condition is false
18
Taking false branch
158 xmmsc_ipc_result_unregister (res->ipc, res);
159 }
160
161 if (res->data) {
19
Assuming the condition is false
20
Taking false branch
162 xmmsv_unref (res->data);
163 }
164
165 xmmsc_result_notifier_delete_all (res);
166
167 free (res);
21
Memory is released
168}
169
170/**
171 * Get the class of the result (default, signal, broadcast).
172 * @returns The class of the result of type #xmmsc_result_type_t
173 */
174xmmsc_result_type_t
175xmmsc_result_get_class (xmmsc_result_t *res)
176{
177 x_return_val_if_fail (res, XMMSC_RESULT_CLASS_DEFAULT)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 177); return (XMMSC_RESULT_CLASS_DEFAULT); }
;
178
179 return res->type;
180}
181
182/**
183 * Disconnect all notifiers for a signal or a broadcast result.
184 * @param res The result to disconnect, must be of class signal or broadcast.
185 */
186void
187xmmsc_result_disconnect (xmmsc_result_t *res)
188{
189 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 189); return; }
;
190
191 switch (res->type) {
192 case XMMSC_RESULT_CLASS_SIGNAL:
193 case XMMSC_RESULT_CLASS_BROADCAST:
194 case XMMSC_RESULT_CLASS_DEFAULT:
195 xmmsc_result_notifier_delete_all (res);
196 break;
197 default:
198 x_api_error_if (1, "invalid result type",)if (1) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "%s was called %s"
, __FUNCTION__, ("invalid result type")); return ; }
;
199 }
200}
201
202static void
203xmmsc_result_restart (xmmsc_result_t *res)
204{
205 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 205); return; }
;
206 x_return_if_fail (res->c)if (!(res->c)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "res->c", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 206); return; }
;
207
208 if (res->type != XMMSC_RESULT_CLASS_SIGNAL) {
209 x_api_warning ("result is not restartable")xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "%s was called %s"
, __FUNCTION__, ("result is not restartable"))
;
210 return;
211 }
212
213 res->cookie = xmmsc_write_signal_msg (res->c, res->restart_signal);
214}
215
216static bool_Bool
217xmmsc_result_parse_msg (xmmsc_result_t *res, xmms_ipc_msg_t *msg)
218{
219 if (xmms_ipc_msg_get_cmd (msg) == XMMS_IPC_COMMAND_ERROR) {
220 /* If special error msg, extract the error and save in result */
221 const char *errstr;
222 xmmsv_t *error;
223
224 if (!xmms_ipc_msg_get_value (msg, &error)) {
225 xmmsc_result_seterror (res, "No error value!");
226 } else {
227 if (!xmmsv_get_error (error, &errstr)) {
228 xmmsc_result_seterror (res, "No error message!");
229 } else {
230 xmmsc_result_seterror (res, errstr);
231 }
232
233 xmmsv_unref (error);
234 }
235
236 res->parsed = true1;
237 return true1;
238 } else if (xmms_ipc_msg_get_value (msg, &res->data)) {
239 /* Expected message data retrieved! */
240 res->parsed = true1;
241 return true1;
242 } else {
243 /* FIXME: shouldn't parsed be false then? */
244 return false0;
245 }
246}
247
248
249/**
250 * return the cookie of a resultset.
251 */
252uint32_t
253xmmsc_result_cookie_get (xmmsc_result_t *res)
254{
255 x_return_val_if_fail (res, 0)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 255); return (0); }
;
256
257 return res->cookie;
258}
259
260/**
261 * Set a result to be a client-to-client result.
262 */
263void
264xmmsc_result_c2c_set (xmmsc_result_t *res)
265{
266 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 266); return; }
;
267
268 res->is_c2c = true1;
269}
270
271void
272xmmsc_result_visc_set (xmmsc_result_t *res, xmmsc_visualization_t *visc)
273{
274 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 274); return; }
;
275 x_return_if_fail (!res->visc)if (!(!res->visc)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "!res->visc", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 275); return; }
;
276 res->visc = visc;
277}
278
279xmmsc_visualization_t *
280xmmsc_result_visc_get (xmmsc_result_t *res)
281{
282 x_return_val_if_fail (res, NULL)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 282); return (((void*)0)); }
;
283 x_return_val_if_fail (res->visc, NULL)if (!(res->visc)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "res->visc", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 283); return (((void
*)0)); }
;
284 return res->visc;
285}
286
287xmmsc_connection_t *
288xmmsc_result_get_connection (xmmsc_result_t *res)
289{
290 x_return_val_if_fail (res, NULL)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 290); return (((void*)0)); }
;
291 x_return_val_if_fail (res->c, NULL)if (!(res->c)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "res->c", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 291); return (((void
*)0)); }
;
292 return res->c;
293}
294
295/**
296 * Decreases the references for the #xmmsc_result_t
297 * When the number of references reaches 0 it will
298 * be freed. And thus all data you extracted from it
299 * will be deallocated.
300 */
301
302void
303xmmsc_result_unref (xmmsc_result_t *res)
304{
305 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 305); return; }
;
306 x_api_error_if (res->ref < 1, "with a freed result",)if (res->ref < 1) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "%s was called %s", __FUNCTION__, ("with a freed result"));
return ; }
;
307
308 res->ref--;
309 if (res->ref == 0) {
14
Assuming the condition is true
15
Taking true branch
310 xmmsc_result_free (res);
16
Calling 'xmmsc_result_free'
22
Returning; memory was released via 1st parameter
311 }
312}
313
314/* Macro magic to define the xmmsc_result_*_notifier_set. */
315#define GEN_RESULT_NOTIFIER_SET_FUNC(type)void xmmsc_result_notifier_set_type (xmmsc_result_t *res, xmmsc_result_notifier_t
func, void *user_data) { xmmsc_result_notifier_set_type_full
(res, func, user_data, ((void*)0)); }
\
316void \
317xmmsc_result_notifier_set_##type (xmmsc_result_t *res, \
318 xmmsc_result_notifier_t func, \
319 void *user_data) \
320{ \
321 xmmsc_result_notifier_set_##type##_full (res, func, user_data, NULL((void*)0)); \
322}
323
324/* And more macro magic to define the xmmsc_result_*_notifier_set_full. */
325#define GEN_RESULT_NOTIFIER_SET_FULL_FUNC(type)void xmmsc_result_notifier_set_type_full (xmmsc_result_t *res
, xmmsc_result_notifier_t func, void *user_data, xmmsc_user_data_free_func_t
free_func) { xmmsc_result_callback_t *cb; if (!(res)) { xmmsc_log
("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 325); return; }; if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 325); return; }; cb = xmmsc_result_callback_new_type (func,
user_data, free_func); xmmsc_result_notifier_add (res, cb); }
\
326void \
327xmmsc_result_notifier_set_##type##_full (xmmsc_result_t *res, \
328 xmmsc_result_notifier_t func, \
329 void *user_data, \
330 xmmsc_user_data_free_func_t free_func) \
331{ \
332 xmmsc_result_callback_t *cb; \
333\
334 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 334); return; }
; \
335 x_return_if_fail (func)if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 335); return; }
; \
336\
337 cb = xmmsc_result_callback_new_##type (func, user_data, free_func); \
338 xmmsc_result_notifier_add (res, cb); \
339}
340
341/**
342 * Set up a default callback for the result retrieval. This callback
343 * will be called when the answer arrives.
344 * The callback receives the value as sent by the server or another
345 * client, that is, for c2c messages only the payload is passed to the
346 * callback.
347 * @param res a #xmmsc_result_t that you got from a command dispatcher.
348 * @param func the function that should be called when we receive the answer
349 * @param user_data optional user data to the callback
350 */
351
352GEN_RESULT_NOTIFIER_SET_FUNC (default)void xmmsc_result_notifier_set_default (xmmsc_result_t *res, xmmsc_result_notifier_t
func, void *user_data) { xmmsc_result_notifier_set_default_full
(res, func, user_data, ((void*)0)); }
353
354/**
355 * Set up a default callback for the result retrieval. This callback
356 * will be called when the answer arrives. This function differs from
357 * xmmsc_result_default_notifier_set in the additional free_func parameter,
358 * which allows to pass a pointer to a function which will be called
359 * to free the user_data when needed.
360 * @param res a #xmmsc_result_t that you got from a command dispatcher.
361 * @param func the function that should be called when we receive the answer
362 * @param user_data optional user data to the callback
363 * @param free_func optional function that should be called to free the user_data
364 */
365
366GEN_RESULT_NOTIFIER_SET_FULL_FUNC (default)void xmmsc_result_notifier_set_default_full (xmmsc_result_t *
res, xmmsc_result_notifier_t func, void *user_data, xmmsc_user_data_free_func_t
free_func) { xmmsc_result_callback_t *cb; if (!(res)) { xmmsc_log
("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 366); return; }; if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 366); return; }; cb = xmmsc_result_callback_new_default (func
, user_data, free_func); xmmsc_result_notifier_add (res, cb);
}
367
368/**
369 * Set up a raw callback for the result retrieval. This callback
370 * will be called when the answer arrives.
371 * The client receives the value sent by the server or, for
372 * client-to-client messages, the full message, whose fields can
373 * be extracted with the appropriate functions.
374 * @param res a #xmmsc_result_t that you got from a command dispatcher.
375 * @param func the function that should be called when we receive the answer
376 * @param user_data optional user data to the callback
377 *
378 * \sa xmmsv_c2c_message_get_payload and others.
379 */
380
381GEN_RESULT_NOTIFIER_SET_FUNC (raw)void xmmsc_result_notifier_set_raw (xmmsc_result_t *res, xmmsc_result_notifier_t
func, void *user_data) { xmmsc_result_notifier_set_raw_full (
res, func, user_data, ((void*)0)); }
382
383/**
384 * Set up a raw callback for the result retrieval. This callback
385 * will be called when the answer arrives. This function differs from
386 * xmmsc_result_raw_notifier_set in the additional free_func parameter,
387 * which allows to pass a pointer to a function which will be called
388 * to free the user_data when needed.
389 * @param res a #xmmsc_result_t that you got from a command dispatcher.
390 * @param func the function that should be called when we receive the answer
391 * @param user_data optional user data to the callback
392 * @param free_func optional function that should be called to free the user_data
393 */
394
395GEN_RESULT_NOTIFIER_SET_FULL_FUNC (raw)void xmmsc_result_notifier_set_raw_full (xmmsc_result_t *res,
xmmsc_result_notifier_t func, void *user_data, xmmsc_user_data_free_func_t
free_func) { xmmsc_result_callback_t *cb; if (!(res)) { xmmsc_log
("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 395); return; }; if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 395); return; }; cb = xmmsc_result_callback_new_raw (func, user_data
, free_func); xmmsc_result_notifier_add (res, cb); }
396
397/**
398 * Set up a c2c callback for the result retrieval. This callback
399 * will be called when the answer arrives.
400 * This callback always receives values formatted as client-to-client
401 * messages, whose fields can be extracted with the appropriate functions.
402 * For values sent by the server, the sender id and message id fields
403 * will be zero.
404 * @param res a #xmmsc_result_t that you got from a command dispatcher.
405 * @param func the function that should be called when we receive the answer
406 * @param user_data optional user data to the callback
407 *
408 * \sa xmmsv_c2c_message_get_payload and others.
409 */
410
411GEN_RESULT_NOTIFIER_SET_FUNC (c2c)void xmmsc_result_notifier_set_c2c (xmmsc_result_t *res, xmmsc_result_notifier_t
func, void *user_data) { xmmsc_result_notifier_set_c2c_full (
res, func, user_data, ((void*)0)); }
412
413/**
414 * Set up a c2c callback for the result retrieval. This callback
415 * will be called when the answer arrives. This function differs from
416 * xmmsc_result_c2c_notifier_set in the additional free_func parameter,
417 * which allows to pass a pointer to a function which will be called
418 * to free the user_data when needed.
419 * @param res a #xmmsc_result_t that you got from a command dispatcher.
420 * @param func the function that should be called when we receive the answer
421 * @param user_data optional user data to the callback
422 * @param free_func optional function that should be called to free the user_data
423 */
424
425GEN_RESULT_NOTIFIER_SET_FULL_FUNC (c2c)void xmmsc_result_notifier_set_c2c_full (xmmsc_result_t *res,
xmmsc_result_notifier_t func, void *user_data, xmmsc_user_data_free_func_t
free_func) { xmmsc_result_callback_t *cb; if (!(res)) { xmmsc_log
("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 425); return; }; if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 425); return; }; cb = xmmsc_result_callback_new_c2c (func, user_data
, free_func); xmmsc_result_notifier_add (res, cb); }
426
427/**
428 * Block for the reply. In a synchronous application this
429 * can be used to wait for the result. Will return when
430 * the server replyed.
431 */
432
433void
434xmmsc_result_wait (xmmsc_result_t *res)
435{
436 const char *err = NULL((void*)0);
437 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 437); return; }
;
438 x_return_if_fail (res->ipc)if (!(res->ipc)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "res->ipc", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 438); return; }
;
439
440 while (!res->parsed && !(err = xmmsc_ipc_error_get (res->ipc))) {
441 xmmsc_ipc_wait_for_event (res->ipc, 5);
442 }
443
444 if (err) {
445 /* FIXME: xmmsv_unref (res->data) or not allocated ? */
446 res->data = xmmsv_new_error (err);
447 }
448}
449
450/**
451 * @defgroup ResultValueRetrieval ResultValueRetrieval
452 * @ingroup Result
453 * @brief Explains how you can retrive values from a #xmmsc_result_t
454 * @{
455 */
456
457/**
458 * Get the value from a result. The reference is still owned by the
459 * result.
460 *
461 * @param res a #xmmsc_result_t containing the value.
462 * @returns A borrowed reference to the value received by the result.
463 */
464xmmsv_t *
465xmmsc_result_get_value (xmmsc_result_t *res)
466{
467 x_return_val_if_fail (res, NULL)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 467); return (((void*)0)); }
;
468 x_return_val_if_fail (res->parsed, NULL)if (!(res->parsed)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL
, "Check '%s' failed in %s at %s:%d", "res->parsed", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 468); return (((void
*)0)); }
;
469
470 return res->data;
471}
472
473/** @} */
474
475/** @} */
476
477/** @internal */
478
479/* Kept as a proxy for external use */
480void
481xmmsc_result_seterror (xmmsc_result_t *res, const char *errstr)
482{
483 if (res->data) {
484 xmmsv_unref (res->data);
485 }
486 res->data = xmmsv_new_error (errstr);
487}
488
489void
490xmmsc_result_restartable (xmmsc_result_t *res, uint32_t signalid)
491{
492 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 492); return; }
;
493
494 res->restart_signal = signalid;
495}
496
497/**
498 * Helper for xmmsc_result_run.
499 * Correctly calls a callback based on its type.
500 * @param res The result that owns the callback
501 * @param cb The callback to be called
502 * @return The result of the callback
503 */
504static int
505xmmsc_result_run_callback (xmmsc_result_t *res, xmmsc_result_callback_t *cb)
506{
507 int ret;
508 xmmsv_t *val = NULL((void*)0);
509
510 if (res->is_c2c && !xmmsv_is_error (res->data)) {
511 if (cb->type == XMMSC_RESULT_CALLBACK_DEFAULT) {
512 /* For default callbacks, pass the payload in c2c
513 * messages.
514 */
515 val = xmmsv_ref (xmmsv_c2c_message_get_payload (res->data));
516 }
517 } else {
518 if (cb->type == XMMSC_RESULT_CALLBACK_C2C) {
519 /* For c2c callbacks and non-c2c messages, build a
520 * message with pseudo c2c metadata.
521 */
522 val = xmmsv_c2c_message_format (0, 0, 0, res->data);
523 }
524 }
525
526 if (!val) {
527 val = xmmsv_ref (res->data);
528 }
529
530 ret = cb->func (val, cb->user_data);
531
532 xmmsv_unref (val);
533 return ret;
534}
535
536/**
537 * @internal
538 */
539void
540xmmsc_result_run (xmmsc_result_t *res, xmms_ipc_msg_t *msg)
541{
542 x_list_t *n, *next;
543 xmmsc_result_callback_t *cb;
544
545 x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 545); return; }
;
1
Within the expansion of the macro 'x_return_if_fail':
a
Assuming 'res' is non-null
546 x_return_if_fail (msg)if (!(msg)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d"
, "msg", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c"
, 546); return; }
;
547
548 if (!xmmsc_result_parse_msg (res, msg)) {
2
Taking false branch
549 xmms_ipc_msg_destroy (msg);
550 return;
551 }
552
553 xmms_ipc_msg_destroy (msg);
554
555 xmmsc_result_ref (res);
556
557 /* Run all notifiers and check for positive return values */
558 n = res->notifiers;
559 while (n) {
3
Loop condition is true. Entering loop body
7
Loop condition is true. Entering loop body
26
Loop condition is true. Entering loop body
560 int keep;
561
562 next = x_list_next (n)((n) ? (((x_list_t *)(n))->next) : ((void*)0));
563 cb = n->data;
564
565 keep = xmmsc_result_run_callback (res, cb);
27
Use of memory after it is freed
566 if (!keep || res->type == XMMSC_RESULT_CLASS_DEFAULT) {
4
Assuming 'keep' is not equal to 0
5
Assuming the condition is false
6
Taking false branch
8
Assuming 'keep' is 0
567 xmmsc_result_notifier_delete (res, n);
9
Calling 'xmmsc_result_notifier_delete'
25
Returning; memory was released via 1st parameter
568 }
569
570 n = next;
571 }
572
573 /* If this result is a signal, and we still have some notifiers
574 * we need to restart the signal.
575 */
576 if (res->notifiers && res->type == XMMSC_RESULT_CLASS_SIGNAL) {
577 /* We restart the signal using the same result. */
578 xmmsc_result_restart (res);
579 }
580
581 if (res->type != XMMSC_RESULT_CLASS_DEFAULT && !res->is_c2c) {
582 /* We keep the results alive with signals and broadcasts,
583 but we just renew the value because it went out of scope.
584 (freeing the payload, forget about it).
585 The exception being for c2c results of the BROADCAST class
586 (those associated with messages and replies), which may be
587 used synchronously as if they belonged to the DEFAULT class.
588 */
589 xmmsv_unref (res->data);
590 res->data = NULL((void*)0);
591 }
592
593 xmmsc_result_unref (res);
594}
595
596/**
597 * Allocates new #xmmsc_result_t and references it.
598 * Should not be used from a client.
599 * @internal
600 */
601
602xmmsc_result_t *
603xmmsc_result_new (xmmsc_connection_t *c, xmmsc_result_type_t type,
604 uint32_t cookie)
605{
606 xmmsc_result_t *res;
607
608 res = x_new0 (xmmsc_result_t, 1)calloc (1, sizeof (xmmsc_result_t) * (1));
609 if (!res) {
610 x_oom ()xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d"
, __FUNCTION__, "../src/clients/lib/xmmsclient/result.c", 610
)
;
611 return NULL((void*)0);
612 }
613
614 res->c = c;
615
616 res->data = NULL((void*)0);
617 res->type = type;
618 res->cookie = cookie;
619
620 /* user must give this back */
621 xmmsc_result_ref (res);
622
623 /* Add it to the loop */
624 xmmsc_ipc_result_register (c->ipc, res);
625
626 /* For the destroy func */
627 res->ipc = c->ipc;
628
629 return res;
630}
631
632void
633xmmsc_result_clear_weakrefs (xmmsc_result_t *result)
634{
635 result->c = NULL((void*)0);
636 result->ipc = NULL((void*)0);
637}
638
639/* Macro-magically define the xmmsc_result_callback_new_* functions. */
640#define GEN_RESULT_CALLBACK_NEW_FUNC(name, cbtype)static xmmsc_result_callback_t * xmmsc_result_callback_new_name
(xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t
free_f) { xmmsc_result_callback_t *cb; cb = calloc (1, sizeof
(xmmsc_result_callback_t) * (1)); if (!cb) { xmmsc_log ("xmmsclient"
, XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 640); return ((void
*)0); } cb->type = cbtype; cb->user_data = udata; cb->
free_func = free_f; cb->func = f; return cb; }
\
641static xmmsc_result_callback_t * \
642xmmsc_result_callback_new_##name (xmmsc_result_notifier_t f, void *udata, \
643 xmmsc_user_data_free_func_t free_f) \
644{ \
645 xmmsc_result_callback_t *cb; \
646\
647 cb = x_new0 (xmmsc_result_callback_t, 1)calloc (1, sizeof (xmmsc_result_callback_t) * (1)); \
648 if (!cb) { \
649 x_oom()xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d"
, __FUNCTION__, "../src/clients/lib/xmmsclient/result.c", 649
)
; \
650 return NULL((void*)0); \
651 } \
652\
653 cb->type = cbtype; \
654 cb->user_data = udata; \
655 cb->free_func = free_f; \
656 cb->func = f; \
657\
658 return cb; \
659}
660
661GEN_RESULT_CALLBACK_NEW_FUNC (default, XMMSC_RESULT_CALLBACK_DEFAULT)static xmmsc_result_callback_t * xmmsc_result_callback_new_default
(xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t
free_f) { xmmsc_result_callback_t *cb; cb = calloc (1, sizeof
(xmmsc_result_callback_t) * (1)); if (!cb) { xmmsc_log ("xmmsclient"
, XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 661); return ((void
*)0); } cb->type = XMMSC_RESULT_CALLBACK_DEFAULT; cb->user_data
= udata; cb->free_func = free_f; cb->func = f; return cb
; }
662GEN_RESULT_CALLBACK_NEW_FUNC (raw, XMMSC_RESULT_CALLBACK_RAW)static xmmsc_result_callback_t * xmmsc_result_callback_new_raw
(xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t
free_f) { xmmsc_result_callback_t *cb; cb = calloc (1, sizeof
(xmmsc_result_callback_t) * (1)); if (!cb) { xmmsc_log ("xmmsclient"
, XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 662); return ((void
*)0); } cb->type = XMMSC_RESULT_CALLBACK_RAW; cb->user_data
= udata; cb->free_func = free_f; cb->func = f; return cb
; }
663GEN_RESULT_CALLBACK_NEW_FUNC (c2c, XMMSC_RESULT_CALLBACK_C2C)static xmmsc_result_callback_t * xmmsc_result_callback_new_c2c
(xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t
free_f) { xmmsc_result_callback_t *cb; cb = calloc (1, sizeof
(xmmsc_result_callback_t) * (1)); if (!cb) { xmmsc_log ("xmmsclient"
, XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d", __FUNCTION__
, "../src/clients/lib/xmmsclient/result.c", 663); return ((void
*)0); } cb->type = XMMSC_RESULT_CALLBACK_C2C; cb->user_data
= udata; cb->free_func = free_f; cb->func = f; return cb
; }
664
665/* Add a new notifier to a result
666 */
667static void
668xmmsc_result_notifier_add (xmmsc_result_t *res, xmmsc_result_callback_t *cb)
669{
670 /* The pending call takes one ref */
671 xmmsc_result_ref (res);
672 res->notifiers = x_list_append (res->notifiers, cb);
673}
674
675
676/* Dereference a notifier from a result.
677 * The #x_list_t node containing the notifier is passed.
678 */
679static void
680xmmsc_result_notifier_remove (xmmsc_result_t *res, x_list_t *node)
681{
682 free (node->data); /* remove the callback struct, but not the udata */
683 res->notifiers = x_list_delete_link (res->notifiers, node);
684 xmmsc_result_unref (res); /* each cb has a reference to res */
13
Calling 'xmmsc_result_unref'
23
Returning; memory was released via 1st parameter
685}
686
687/* Dereference a notifier from a result and delete its udata.
688 * The #x_list_t node containing the notifier is passed.
689 */
690static void
691xmmsc_result_notifier_delete (xmmsc_result_t *res, x_list_t *node)
692{
693 xmmsc_result_callback_t *cb = node->data;
694
695 /* remove the udata */
696 if (cb->free_func) {
10
Assuming the condition is false
11
Taking false branch
697 cb->free_func (cb->user_data);
698 }
699 xmmsc_result_notifier_remove (res, node);
12
Calling 'xmmsc_result_notifier_remove'
24
Returning; memory was released via 1st parameter
700}
701
702/* Dereference all notifiers from a result and delete their udata. */
703static void
704xmmsc_result_notifier_delete_all (xmmsc_result_t *res)
705{
706 x_list_t *n = res->notifiers;
707
708 while (n) {
709 x_list_t *next = x_list_next (n)((n) ? (((x_list_t *)(n))->next) : ((void*)0));
710 xmmsc_result_notifier_delete (res, n);
711 n = next;
712 }
713
714 res->notifiers = NULL((void*)0);
715}