PageRenderTime 25ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/virnetdaemontest.c

https://gitlab.com/libvirt/libvirt
C | 427 lines | 325 code | 71 blank | 31 comment | 50 complexity | dba635613facbb35063b751ecd9c8a26 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * Copyright (C) 2015 Red Hat, Inc.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library. If not, see
  16. * <http://www.gnu.org/licenses/>.
  17. */
  18. #include <config.h>
  19. #include <unistd.h>
  20. #include "testutils.h"
  21. #include "virerror.h"
  22. #include "rpc/virnetdaemon.h"
  23. #define VIR_FROM_THIS VIR_FROM_RPC
  24. #if !defined(WIN32) && defined(WITH_YAJL)
  25. struct testClientPriv {
  26. int magic;
  27. };
  28. static void *
  29. testClientNew(virNetServerClientPtr client G_GNUC_UNUSED,
  30. void *opaque G_GNUC_UNUSED)
  31. {
  32. struct testClientPriv *priv;
  33. if (VIR_ALLOC(priv) < 0)
  34. return NULL;
  35. priv->magic = 1729;
  36. return priv;
  37. }
  38. static virJSONValuePtr
  39. testClientPreExec(virNetServerClientPtr client G_GNUC_UNUSED,
  40. void *data)
  41. {
  42. struct testClientPriv *priv = data;
  43. return virJSONValueNewNumberInt(priv->magic);
  44. }
  45. static void *
  46. testClientNewPostExec(virNetServerClientPtr client,
  47. virJSONValuePtr object,
  48. void *opaque)
  49. {
  50. int magic;
  51. if (virJSONValueGetNumberInt(object, &magic) < 0)
  52. return NULL;
  53. if (magic != 1729)
  54. return NULL;
  55. return testClientNew(client, opaque);
  56. }
  57. static void
  58. testClientFree(void *opaque)
  59. {
  60. VIR_FREE(opaque);
  61. }
  62. static virNetServerPtr
  63. testCreateServer(const char *server_name, const char *host, int family)
  64. {
  65. virNetServerPtr srv = NULL;
  66. virNetServerServicePtr svc1 = NULL, svc2 = NULL;
  67. virNetServerClientPtr cln1 = NULL, cln2 = NULL;
  68. virNetSocketPtr sk1 = NULL, sk2 = NULL;
  69. int fdclient[2];
  70. if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdclient) < 0) {
  71. virReportSystemError(errno, "%s",
  72. "Cannot create socket pair");
  73. goto cleanup;
  74. }
  75. if (!(srv = virNetServerNew(server_name, 1,
  76. 10, 50, 5, 100, 10,
  77. 120, 5,
  78. testClientNew,
  79. testClientPreExec,
  80. testClientFree,
  81. NULL)))
  82. goto error;
  83. if (!(svc1 = virNetServerServiceNewTCP(host,
  84. NULL,
  85. family,
  86. VIR_NET_SERVER_SERVICE_AUTH_NONE,
  87. NULL,
  88. true,
  89. 5,
  90. 2)))
  91. goto error;
  92. if (!(svc2 = virNetServerServiceNewTCP(host,
  93. NULL,
  94. family,
  95. VIR_NET_SERVER_SERVICE_AUTH_POLKIT,
  96. NULL,
  97. false,
  98. 25,
  99. 5)))
  100. goto error;
  101. if (virNetServerAddService(srv, svc1) < 0)
  102. goto error;
  103. if (virNetServerAddService(srv, svc2) < 0)
  104. goto error;
  105. if (virNetSocketNewConnectSockFD(fdclient[0], &sk1) < 0)
  106. goto error;
  107. if (virNetSocketNewConnectSockFD(fdclient[1], &sk2) < 0)
  108. goto error;
  109. if (!(cln1 = virNetServerClientNew(virNetServerNextClientID(srv),
  110. sk1,
  111. VIR_NET_SERVER_SERVICE_AUTH_SASL,
  112. true,
  113. 15,
  114. NULL,
  115. testClientNew,
  116. testClientPreExec,
  117. testClientFree,
  118. NULL)))
  119. goto error;
  120. if (!(cln2 = virNetServerClientNew(virNetServerNextClientID(srv),
  121. sk2,
  122. VIR_NET_SERVER_SERVICE_AUTH_POLKIT,
  123. true,
  124. 66,
  125. NULL,
  126. testClientNew,
  127. testClientPreExec,
  128. testClientFree,
  129. NULL)))
  130. goto error;
  131. if (virNetServerAddClient(srv, cln1) < 0)
  132. goto error;
  133. if (virNetServerAddClient(srv, cln2) < 0)
  134. goto error;
  135. cleanup:
  136. if (!srv)
  137. virDispatchError(NULL);
  138. virObjectUnref(cln1);
  139. virObjectUnref(cln2);
  140. virObjectUnref(svc1);
  141. virObjectUnref(svc2);
  142. virObjectUnref(sk1);
  143. virObjectUnref(sk2);
  144. return srv;
  145. error:
  146. virObjectUnref(srv);
  147. srv = NULL;
  148. goto cleanup;
  149. }
  150. static char *testGenerateJSON(const char *server_name)
  151. {
  152. virNetDaemonPtr dmn = NULL;
  153. virNetServerPtr srv = NULL;
  154. virJSONValuePtr json = NULL;
  155. char *jsonstr = NULL;
  156. bool has_ipv4, has_ipv6;
  157. /* Our pre-saved JSON file is created so that each service
  158. * only has one socket. If we let libvirt bind to IPv4 and
  159. * IPv6 we might end up with two sockets, so force one or
  160. * the other based on what's available on thehost
  161. */
  162. if (virNetSocketCheckProtocols(&has_ipv4,
  163. &has_ipv6) < 0)
  164. return NULL;
  165. if (!has_ipv4 && !has_ipv6)
  166. return NULL;
  167. if (!(srv = testCreateServer(server_name,
  168. has_ipv4 ? "127.0.0.1" : "::1",
  169. has_ipv4 ? AF_INET : AF_INET6)))
  170. goto cleanup;
  171. if (!(dmn = virNetDaemonNew()))
  172. goto cleanup;
  173. if (virNetDaemonAddServer(dmn, srv) < 0)
  174. goto cleanup;
  175. if (!(json = virNetDaemonPreExecRestart(dmn)))
  176. goto cleanup;
  177. if (!(jsonstr = virJSONValueToString(json, true)))
  178. goto cleanup;
  179. fprintf(stderr, "%s\n", jsonstr);
  180. cleanup:
  181. virNetServerClose(srv);
  182. virObjectUnref(srv);
  183. virObjectUnref(dmn);
  184. virJSONValueFree(json);
  185. if (!jsonstr)
  186. virDispatchError(NULL);
  187. return jsonstr;
  188. }
  189. struct testExecRestartData {
  190. const char *jsonfile;
  191. const char **serverNames;
  192. int nservers;
  193. bool pass;
  194. };
  195. static virNetServerPtr
  196. testNewServerPostExecRestart(virNetDaemonPtr dmn G_GNUC_UNUSED,
  197. const char *name,
  198. virJSONValuePtr object,
  199. void *opaque)
  200. {
  201. struct testExecRestartData *data = opaque;
  202. size_t i;
  203. for (i = 0; i < data->nservers; i++) {
  204. if (STREQ(data->serverNames[i], name)) {
  205. return virNetServerNewPostExecRestart(object,
  206. name,
  207. testClientNew,
  208. testClientNewPostExec,
  209. testClientPreExec,
  210. testClientFree,
  211. NULL);
  212. }
  213. }
  214. virReportError(VIR_ERR_INTERNAL_ERROR, "Unexpected server name '%s'", name);
  215. return NULL;
  216. }
  217. static int testExecRestart(const void *opaque)
  218. {
  219. size_t i;
  220. int ret = -1;
  221. virNetDaemonPtr dmn = NULL;
  222. const struct testExecRestartData *data = opaque;
  223. char *infile = NULL, *outfile = NULL;
  224. char *injsonstr = NULL, *outjsonstr = NULL;
  225. virJSONValuePtr injson = NULL, outjson = NULL;
  226. int fdclient[2] = { -1, -1 }, fdserver[2] = { -1, -1 };
  227. if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdclient) < 0) {
  228. virReportSystemError(errno, "%s",
  229. "Cannot create socket pair");
  230. goto cleanup;
  231. }
  232. if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdserver) < 0) {
  233. virReportSystemError(errno, "%s",
  234. "Cannot create socket pair");
  235. goto cleanup;
  236. }
  237. /* We're blindly assuming the test case isn't using
  238. * fds 100->103 for something else, which is probably
  239. * fairly reasonable in general
  240. */
  241. if (dup2(fdserver[0], 100) < 0 ||
  242. dup2(fdserver[1], 101) < 0 ||
  243. dup2(fdclient[0], 102) < 0 ||
  244. dup2(fdclient[1], 103) < 0) {
  245. virReportSystemError(errno, "%s", "dup2() failed");
  246. goto cleanup;
  247. }
  248. infile = g_strdup_printf("%s/virnetdaemondata/input-data-%s.json", abs_srcdir,
  249. data->jsonfile);
  250. outfile = g_strdup_printf("%s/virnetdaemondata/output-data-%s.json",
  251. abs_srcdir, data->jsonfile);
  252. if (virFileReadAll(infile, 8192, &injsonstr) < 0)
  253. goto cleanup;
  254. if (!(injson = virJSONValueFromString(injsonstr)))
  255. goto cleanup;
  256. if (!(dmn = virNetDaemonNewPostExecRestart(injson,
  257. data->nservers,
  258. data->serverNames,
  259. testNewServerPostExecRestart,
  260. (void *)data)))
  261. goto cleanup;
  262. for (i = 0; i < data->nservers; i++) {
  263. if (!virNetDaemonHasServer(dmn, data->serverNames[i])) {
  264. virReportError(VIR_ERR_INTERNAL_ERROR,
  265. "Server %s was not created",
  266. data->serverNames[i]);
  267. goto cleanup;
  268. }
  269. }
  270. if (!(outjson = virNetDaemonPreExecRestart(dmn)))
  271. goto cleanup;
  272. if (!(outjsonstr = virJSONValueToString(outjson, true)))
  273. goto cleanup;
  274. if (virTestCompareToFile(outjsonstr, outfile) < 0)
  275. goto cleanup;
  276. ret = 0;
  277. cleanup:
  278. if (ret < 0) {
  279. if (!data->pass) {
  280. VIR_TEST_DEBUG("Got expected error: %s",
  281. virGetLastErrorMessage());
  282. virResetLastError();
  283. ret = 0;
  284. }
  285. } else if (!data->pass) {
  286. VIR_TEST_DEBUG("Test should have failed");
  287. ret = -1;
  288. }
  289. VIR_FREE(infile);
  290. VIR_FREE(outfile);
  291. VIR_FREE(injsonstr);
  292. VIR_FREE(outjsonstr);
  293. virJSONValueFree(injson);
  294. virJSONValueFree(outjson);
  295. virObjectUnref(dmn);
  296. VIR_FORCE_CLOSE(fdserver[0]);
  297. VIR_FORCE_CLOSE(fdserver[1]);
  298. VIR_FORCE_CLOSE(fdclient[0]);
  299. VIR_FORCE_CLOSE(fdclient[1]);
  300. return ret;
  301. }
  302. static int
  303. mymain(void)
  304. {
  305. int ret = 0;
  306. const char *server_names[] = { "testServer0", "testServer1" };
  307. if (virInitialize() < 0 ||
  308. virEventRegisterDefaultImpl() < 0) {
  309. virDispatchError(NULL);
  310. return EXIT_FAILURE;
  311. }
  312. /* Hack to make it easier to generate new JSON files when
  313. * the RPC classes change. Just set this env var, save
  314. * the generated JSON, and replace the file descriptor
  315. * numbers with 100, 101, 102, 103.
  316. */
  317. if (getenv("VIR_GENERATE_JSON")) {
  318. char *json = testGenerateJSON(server_names[0]);
  319. if (!json)
  320. return EXIT_FAILURE;
  321. fprintf(stdout, "%s\n", json);
  322. VIR_FREE(json);
  323. return ret;
  324. }
  325. # define EXEC_RESTART_TEST_FULL(file, nservers, pass) \
  326. do { \
  327. struct testExecRestartData data = { \
  328. file, server_names, nservers, pass \
  329. }; \
  330. if (virTestRun("ExecRestart " file, \
  331. testExecRestart, &data) < 0) \
  332. ret = -1; \
  333. } while (0)
  334. # define EXEC_RESTART_TEST(file, N) EXEC_RESTART_TEST_FULL(file, N, true)
  335. # define EXEC_RESTART_TEST_FAIL(file, N) EXEC_RESTART_TEST_FULL(file, N, false)
  336. EXEC_RESTART_TEST("initial", 1);
  337. EXEC_RESTART_TEST("anon-clients", 1);
  338. EXEC_RESTART_TEST("admin", 2);
  339. EXEC_RESTART_TEST("admin-server-names", 2);
  340. EXEC_RESTART_TEST("no-keepalive-required", 2);
  341. EXEC_RESTART_TEST("client-ids", 1);
  342. EXEC_RESTART_TEST("client-timestamp", 1);
  343. EXEC_RESTART_TEST_FAIL("anon-clients", 2);
  344. EXEC_RESTART_TEST("client-auth-pending", 1);
  345. EXEC_RESTART_TEST_FAIL("client-auth-pending-failure", 1);
  346. return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
  347. }
  348. VIR_TEST_MAIN_PRELOAD(mymain, VIR_TEST_MOCK("virnetdaemon"))
  349. #else
  350. static int
  351. mymain(void)
  352. {
  353. return EXIT_AM_SKIP;
  354. }
  355. VIR_TEST_MAIN(mymain);
  356. #endif