2 * remote.c: XML-RPC based remote extension for libvsccli
4 * Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.com>
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.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <xmlrpc-c/base.h>
24 #include <xmlrpc-c/client.h>
26 #include <libvscmisc/assert.h>
27 #include <libvscmisc/error.h>
28 #include <libvscmisc/memory.h>
29 #include <libvscmisc/string.h>
31 #include <libvsccli/option.h>
33 #include "../include/libvscremote/libvscremote.h"
35 static int _initialized = FALSE;
36 static VscRemoteMethodNameLookupFunction _method_name_lookup_function = NULL;
37 static VscRemoteArgumentNameLookupFunction _argument_name_lookup_function = NULL;
38 static char *_remote_url = NULL;
39 static char *_username = NULL;
40 static char *_cookie = NULL;
43 _error_from_xmlrpc (struct VscError *error, const xmlrpc_env *env,
44 const char *file, const char *function, int line)
46 vsc_error_report (error, VSC__ERROR_CODE__XMLRPC_ERROR, file, line,
47 function, "%s (%d)", env->fault_string,
51 #define _ERROR_FROM_XMLRPC(error, env) \
52 _error_from_xmlrpc (error, env, __FILE__, __FUNCTION__, __LINE__)
55 _request_password (struct VscError *error, const char *username)
57 struct termios old, new;
58 char *password = NULL;
61 VSC__ASSERT (error != NULL);
62 VSC__ASSERT (! error->occured);
64 password = vsc_alloc (error, size);
67 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
71 if (tcgetattr (fileno (stdin), &old) != 0) {
72 VSC__ERROR1 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
80 if (tcsetattr (fileno (stdin), TCSAFLUSH, &new) != 0) {
81 VSC__ERROR1 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
86 printf ("Enter password for %s: ", username);
88 if (fgets (password, size, stdin) == NULL) {
92 if (password != NULL) {
93 size = strlen (password);
96 password[size - 1] = '\0';
100 (void) tcsetattr (fileno (stdin), TCSAFLUSH, &old);
108 _lookup_method_name (struct VscError *error, const char *command_name)
110 const char *method_name = NULL;
112 VSC__ASSERT (error != NULL);
113 VSC__ASSERT (! error->occured);
114 VSC__ASSERT (_method_name_lookup_function != NULL);
116 method_name = _method_name_lookup_function (error, command_name);
118 if (error->occured) {
119 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
123 if (method_name == NULL) {
124 VSC__ERROR1 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
133 _lookup_argument_name (struct VscError *error, const char *command_name,
134 const char *option_long_name)
136 const char *argument_name = NULL;
138 VSC__ASSERT (error != NULL);
139 VSC__ASSERT (! error->occured);
140 VSC__ASSERT (_argument_name_lookup_function != NULL);
142 argument_name = _argument_name_lookup_function (error, command_name,
145 if (error->occured) {
146 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
150 if (argument_name == NULL) {
151 VSC__ERROR1 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
156 return argument_name;
164 _login (struct VscError *error, const struct VscCliCommandInfo *command_info,
165 const struct VscCliOption *option_list, void *user_data);
167 static const struct VscCliOptionInfo _login_option_infos[] = {
168 { -1, "username", "username for the remote system",
169 VSC_CLI__OPTION_TYPE__STRING, FALSE, TRUE },
170 { -1, "password", "password for the remote system",
171 VSC_CLI__OPTION_TYPE__STRING, FALSE, FALSE },
172 VSC_CLI__NULL__OPTION_INFO,
175 const struct VscCliCommandInfo vsc_remote_login_command_info = {
177 "login to the remote system",
184 _login (struct VscError *error,
185 const struct VscCliCommandInfo *command_info VSC__ATTR__UNUSED,
186 const struct VscCliOption *option_list,
187 void *user_data VSC__ATTR__UNUSED)
189 const char *method_name;
190 const char *username_name;
191 const char *password_name;
192 const char *username;
193 const char *password;
196 xmlrpc_value *result = NULL;
198 char *message = NULL;
200 VSC__ASSERT (error != NULL);
201 VSC__ASSERT (! error->occured);
203 vsc_remote_check (error, FALSE);
205 if (error->occured) {
206 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
210 method_name = _lookup_method_name (error, "login");
212 if (error->occured) {
213 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
217 username_name = _lookup_argument_name (error, "login", "username");
219 if (error->occured) {
220 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
224 password_name = _lookup_argument_name (error, "login", "password");
226 if (error->occured) {
227 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
231 VSC__ASSERT (_username == NULL);
233 username = vsc_cli_option_get_string (option_list, "username");
234 password = vsc_cli_option_get_string (option_list, "password");
236 VSC__ASSERT (username != NULL);
238 if (password == NULL) {
239 password_ = _request_password (error, username);
241 if (password_ == NULL) {
242 VSC__ERROR1 (error, VSC__ERROR_CODE__INTERNAL_ERROR,
243 "Could not read passowrd");
247 password_ = vsc_strdup (error, password);
249 if (error->occured) {
250 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
255 xmlrpc_env_init (&env);
257 result = xmlrpc_client_call (&env, _remote_url, method_name,
259 username_name, username,
260 password_name, password_);
262 if (env.fault_occurred) {
263 _ERROR_FROM_XMLRPC (error, &env);
268 xmlrpc_decompose_value (&env, result, "{s:i,s:s,s:s,*}",
273 if (env.fault_occurred) {
274 _ERROR_FROM_XMLRPC (error, &env);
280 VSC__ERROR2 (error, VSC__ERROR_CODE__REMOTE_ERROR,
281 "%s (%d)", message, code);
286 _username = vsc_strdup (error, username);
288 if (error->occured) {
289 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
294 if (result != NULL) {
295 xmlrpc_DECREF (result);
298 vsc_free (&password_);
301 xmlrpc_env_clean (&env);
309 _logout (struct VscError *error, const struct VscCliCommandInfo *command_info,
310 const struct VscCliOption *option_list, void *user_data);
312 static const struct VscCliOptionInfo _logout_option_infos[] = {
313 VSC_CLI__NULL__OPTION_INFO,
316 const struct VscCliCommandInfo vsc_remote_logout_command_info = {
318 "logout from the remote system",
321 _logout_option_infos,
325 _logout (struct VscError *error,
326 const struct VscCliCommandInfo *command_info VSC__ATTR__UNUSED,
327 const struct VscCliOption *option_list VSC__ATTR__UNUSED,
328 void *user_data VSC__ATTR__UNUSED)
330 const char *method_name = NULL;
331 const char *cookie_name = NULL;
333 xmlrpc_value *result = NULL;
335 char *message = NULL;
337 VSC__ASSERT (error != NULL);
338 VSC__ASSERT (! error->occured);
340 vsc_remote_check (error, TRUE);
342 if (error->occured) {
343 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
347 method_name = _lookup_method_name (error, "logout");
349 if (error->occured) {
350 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
354 cookie_name = _lookup_argument_name (error, "logout", "cookie");
356 if (error->occured) {
357 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
361 xmlrpc_env_init (&env);
363 result = xmlrpc_client_call (&env, _remote_url, method_name,
365 cookie_name, _cookie);
367 if (env.fault_occurred) {
368 _ERROR_FROM_XMLRPC (error, &env);
373 xmlrpc_decompose_value (&env, result, "{s:i,s:s,*}",
375 "message", &message);
377 if (env.fault_occurred) {
378 _ERROR_FROM_XMLRPC (error, &env);
384 VSC__ERROR2 (error, VSC__ERROR_CODE__REMOTE_ERROR,
385 "%s (%d)", message, code);
390 vsc_free (&_username);
393 if (result != NULL) {
394 xmlrpc_DECREF (result);
399 xmlrpc_env_clean (&env);
407 vsc_remote_init (struct VscError *error, const char *name, const char *version,
408 const char *remote_url,
409 VscRemoteMethodNameLookupFunction method_name_lookup_function,
410 VscRemoteArgumentNameLookupFunction argument_name_lookup_function)
413 char user_agent[256];
414 struct xmlrpc_clientparms clientParms;
415 struct xmlrpc_curl_xportparms curlParms;
417 VSC__ASSERT (error != NULL);
418 VSC__ASSERT (! error->occured);
419 VSC__ASSERT (method_name_lookup_function != NULL);
420 VSC__ASSERT (argument_name_lookup_function != NULL);
423 VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_CALL,
424 "Already initialized");
428 _method_name_lookup_function = method_name_lookup_function;
429 _argument_name_lookup_function = argument_name_lookup_function;
431 if (remote_url != NULL) {
432 _remote_url = vsc_strdup (error, remote_url);
434 if (error->occured) {
435 VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
443 * Configure the XML-RPC-C Curl backend to send a User-Agent.
445 xmlrpc_env_init (&env);
447 memset (&clientParms, 0, sizeof (struct xmlrpc_clientparms));
448 memset (&curlParms, 0, sizeof (struct xmlrpc_curl_xportparms));
450 snprintf (user_agent, 256, "%s/%s", name, version);
452 curlParms.user_agent = user_agent;
454 clientParms.transport = "curl";
455 clientParms.transportparmsP = &curlParms;
456 clientParms.transportparm_size = XMLRPC_CXPSIZE (user_agent);
458 xmlrpc_client_init2 (&env, XMLRPC_CLIENT_NO_FLAGS, name, version,
459 &clientParms, XMLRPC_CPSIZE (transportparm_size));
461 if (env.fault_occurred) {
462 _ERROR_FROM_XMLRPC (error, &env);
469 xmlrpc_env_clean (&env);
473 vsc_remote_cleanup (void)
475 struct VscError error;
477 VSC__ASSERT (_initialized);
479 if (! _initialized) {
484 * FIXME: If an RPC error occured this call segfaults. This only happens if
485 * the XML-RPC-C library is compiled with -O3. If compiled with -O0
486 * everything is fine.
488 xmlrpc_client_cleanup();
490 if (_cookie != NULL) {
491 vsc_error_init (&error);
493 _logout (&error, NULL, NULL, NULL);
495 vsc_error_cleanup (&error);
498 vsc_free (&_remote_url);
500 vsc_free (&_username);
502 _method_name_lookup_function = NULL;
503 _argument_name_lookup_function = NULL;
505 _initialized = FALSE;
509 vsc_remote_check (struct VscError *error, int expected_login_state)
511 VSC__ASSERT (error != NULL);
512 VSC__ASSERT (! error->occured);
514 if (! _initialized) {
515 VSC__ERROR1 (error, VSC__ERROR_CODE__NOT_INITIALIZED,
520 if (_remote_url == NULL) {
521 VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_CALL,
522 "No remote URL specified");
526 if (expected_login_state == TRUE && _cookie == NULL) {
527 VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_CALL, "Not logged in");
531 if (expected_login_state == FALSE && _cookie != NULL) {
532 VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_CALL,
533 "Already logged in");
539 vsc_remote_get_cookie (struct VscError *error)
541 VSC__ASSERT (error != NULL);
542 VSC__ASSERT (! error->occured);
544 if (! _initialized) {
545 VSC__ERROR1 (error, VSC__ERROR_CODE__NOT_INITIALIZED,
550 if (_cookie == NULL) {
551 VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_CALL,
552 "No cookie avaiable");
560 vsc_remote_get_username (struct VscError *error)
562 VSC__ASSERT (error != NULL);
563 VSC__ASSERT (! error->occured);
565 if (! _initialized) {
566 VSC__ERROR1 (error, VSC__ERROR_CODE__NOT_INITIALIZED,