PageRenderTime 68ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 0ms

/avm2_env/usr/src/lib/libc/net/nscachedcli.c

https://gitlab.com/kidaa/crossbridge
C | 576 lines | 406 code | 97 blank | 73 comment | 115 complexity | dc42bdf6b8db82f1b7cf3edf0632af83 MD5 | raw file
Possible License(s): GPL-3.0, Apache-2.0, CC-BY-SA-3.0, LGPL-3.0, MPL-2.0-no-copyleft-exception, GPL-2.0, LGPL-2.1, AGPL-1.0, BSD-3-Clause, LGPL-2.0
  1. /*-
  2. * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. *
  26. */
  27. #include <sys/cdefs.h>
  28. __FBSDID("$FreeBSD: src/lib/libc/net/nscachedcli.c,v 1.3.10.1.6.1 2010/12/21 17:09:25 kensmith Exp $");
  29. #include "namespace.h"
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32. #include <sys/event.h>
  33. #include <sys/uio.h>
  34. #include <sys/un.h>
  35. #include <assert.h>
  36. #include <errno.h>
  37. #include <fcntl.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <unistd.h>
  41. #include "un-namespace.h"
  42. #include "nscachedcli.h"
  43. #define NS_DEFAULT_CACHED_IO_TIMEOUT 4
  44. static int safe_write(struct cached_connection_ *, const void *, size_t);
  45. static int safe_read(struct cached_connection_ *, void *, size_t);
  46. static int send_credentials(struct cached_connection_ *, int);
  47. /*
  48. * safe_write writes data to the specified connection and tries to do it in
  49. * the very safe manner. We ensure, that we can write to the socket with
  50. * kevent. If the data_size can't be sent in one piece, then it would be
  51. * splitted.
  52. */
  53. static int
  54. safe_write(struct cached_connection_ *connection, const void *data,
  55. size_t data_size)
  56. {
  57. struct kevent eventlist;
  58. int nevents;
  59. size_t result;
  60. ssize_t s_result;
  61. struct timespec timeout;
  62. if (data_size == 0)
  63. return (0);
  64. timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT;
  65. timeout.tv_nsec = 0;
  66. result = 0;
  67. do {
  68. nevents = _kevent(connection->write_queue, NULL, 0, &eventlist,
  69. 1, &timeout);
  70. if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) {
  71. s_result = _write(connection->sockfd, data + result,
  72. eventlist.data < data_size - result ?
  73. eventlist.data : data_size - result);
  74. if (s_result == -1)
  75. return (-1);
  76. else
  77. result += s_result;
  78. if (eventlist.flags & EV_EOF)
  79. return (result < data_size ? -1 : 0);
  80. } else
  81. return (-1);
  82. } while (result < data_size);
  83. return (0);
  84. }
  85. /*
  86. * safe_read reads data from connection and tries to do it in the very safe
  87. * and stable way. It uses kevent to ensure, that the data are availabe for
  88. * reading. If the amount of data to be read is too large, then they would
  89. * be splitted.
  90. */
  91. static int
  92. safe_read(struct cached_connection_ *connection, void *data, size_t data_size)
  93. {
  94. struct kevent eventlist;
  95. size_t result;
  96. ssize_t s_result;
  97. struct timespec timeout;
  98. int nevents;
  99. if (data_size == 0)
  100. return (0);
  101. timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT;
  102. timeout.tv_nsec = 0;
  103. result = 0;
  104. do {
  105. nevents = _kevent(connection->read_queue, NULL, 0, &eventlist,
  106. 1, &timeout);
  107. if (nevents == 1 && eventlist.filter == EVFILT_READ) {
  108. s_result = _read(connection->sockfd, data + result,
  109. eventlist.data <= data_size - result ?
  110. eventlist.data : data_size - result);
  111. if (s_result == -1)
  112. return (-1);
  113. else
  114. result += s_result;
  115. if (eventlist.flags & EV_EOF)
  116. return (result < data_size ? -1 : 0);
  117. } else
  118. return (-1);
  119. } while (result < data_size);
  120. return (0);
  121. }
  122. /*
  123. * Sends the credentials information to the connection along with the
  124. * communication element type.
  125. */
  126. static int
  127. send_credentials(struct cached_connection_ *connection, int type)
  128. {
  129. struct kevent eventlist;
  130. int nevents;
  131. ssize_t result;
  132. int res;
  133. struct msghdr cred_hdr;
  134. struct iovec iov;
  135. struct {
  136. struct cmsghdr hdr;
  137. char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
  138. } cmsg;
  139. memset(&cmsg, 0, sizeof(cmsg));
  140. cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
  141. cmsg.hdr.cmsg_level = SOL_SOCKET;
  142. cmsg.hdr.cmsg_type = SCM_CREDS;
  143. memset(&cred_hdr, 0, sizeof(struct msghdr));
  144. cred_hdr.msg_iov = &iov;
  145. cred_hdr.msg_iovlen = 1;
  146. cred_hdr.msg_control = (caddr_t)&cmsg;
  147. cred_hdr.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
  148. iov.iov_base = &type;
  149. iov.iov_len = sizeof(int);
  150. EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
  151. NOTE_LOWAT, sizeof(int), NULL);
  152. res = _kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
  153. nevents = _kevent(connection->write_queue, NULL, 0, &eventlist, 1,
  154. NULL);
  155. if (nevents == 1 && eventlist.filter == EVFILT_WRITE) {
  156. result = (_sendmsg(connection->sockfd, &cred_hdr, 0) == -1) ?
  157. -1 : 0;
  158. EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
  159. 0, 0, NULL);
  160. _kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
  161. return (result);
  162. } else
  163. return (-1);
  164. }
  165. /*
  166. * Opens the connection with the specified params. Initializes all kqueues.
  167. */
  168. struct cached_connection_ *
  169. __open_cached_connection(struct cached_connection_params const *params)
  170. {
  171. struct cached_connection_ *retval;
  172. struct kevent eventlist;
  173. struct sockaddr_un client_address;
  174. int client_address_len, client_socket;
  175. int res;
  176. assert(params != NULL);
  177. client_socket = _socket(PF_LOCAL, SOCK_STREAM, 0);
  178. client_address.sun_family = PF_LOCAL;
  179. strncpy(client_address.sun_path, params->socket_path,
  180. sizeof(client_address.sun_path));
  181. client_address_len = sizeof(client_address.sun_family) +
  182. strlen(client_address.sun_path) + 1;
  183. res = _connect(client_socket, (struct sockaddr *)&client_address,
  184. client_address_len);
  185. if (res == -1) {
  186. _close(client_socket);
  187. return (NULL);
  188. }
  189. _fcntl(client_socket, F_SETFL, O_NONBLOCK);
  190. retval = malloc(sizeof(struct cached_connection_));
  191. assert(retval != NULL);
  192. memset(retval, 0, sizeof(struct cached_connection_));
  193. retval->sockfd = client_socket;
  194. retval->write_queue = kqueue();
  195. assert(retval->write_queue != -1);
  196. EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
  197. res = _kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL);
  198. retval->read_queue = kqueue();
  199. assert(retval->read_queue != -1);
  200. EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
  201. res = _kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL);
  202. return (retval);
  203. }
  204. void
  205. __close_cached_connection(struct cached_connection_ *connection)
  206. {
  207. assert(connection != NULL);
  208. _close(connection->sockfd);
  209. _close(connection->read_queue);
  210. _close(connection->write_queue);
  211. free(connection);
  212. }
  213. /*
  214. * This function is very close to the cache_write function of the caching
  215. * library, which is used in the caching daemon. It caches the data with the
  216. * specified key in the cache entry with entry_name.
  217. */
  218. int
  219. __cached_write(struct cached_connection_ *connection, const char *entry_name,
  220. const char *key, size_t key_size, const char *data, size_t data_size)
  221. {
  222. size_t name_size;
  223. int error_code;
  224. int result;
  225. error_code = -1;
  226. result = 0;
  227. result = send_credentials(connection, CET_WRITE_REQUEST);
  228. if (result != 0)
  229. goto fin;
  230. name_size = strlen(entry_name);
  231. result = safe_write(connection, &name_size, sizeof(size_t));
  232. if (result != 0)
  233. goto fin;
  234. result = safe_write(connection, &key_size, sizeof(size_t));
  235. if (result != 0)
  236. goto fin;
  237. result = safe_write(connection, &data_size, sizeof(size_t));
  238. if (result != 0)
  239. goto fin;
  240. result = safe_write(connection, entry_name, name_size);
  241. if (result != 0)
  242. goto fin;
  243. result = safe_write(connection, key, key_size);
  244. if (result != 0)
  245. goto fin;
  246. result = safe_write(connection, data, data_size);
  247. if (result != 0)
  248. goto fin;
  249. result = safe_read(connection, &error_code, sizeof(int));
  250. if (result != 0)
  251. error_code = -1;
  252. fin:
  253. return (error_code);
  254. }
  255. /*
  256. * This function is very close to the cache_read function of the caching
  257. * library, which is used in the caching daemon. It reads cached data with the
  258. * specified key from the cache entry with entry_name.
  259. */
  260. int
  261. __cached_read(struct cached_connection_ *connection, const char *entry_name,
  262. const char *key, size_t key_size, char *data, size_t *data_size)
  263. {
  264. size_t name_size, result_size;
  265. int error_code, rec_error_code;
  266. int result;
  267. assert(connection != NULL);
  268. result = 0;
  269. error_code = -1;
  270. result = send_credentials(connection, CET_READ_REQUEST);
  271. if (result != 0)
  272. goto fin;
  273. name_size = strlen(entry_name);
  274. result = safe_write(connection, &name_size, sizeof(size_t));
  275. if (result != 0)
  276. goto fin;
  277. result = safe_write(connection, &key_size, sizeof(size_t));
  278. if (result != 0)
  279. goto fin;
  280. result = safe_write(connection, entry_name, name_size);
  281. if (result != 0)
  282. goto fin;
  283. result = safe_write(connection, key, key_size);
  284. if (result != 0)
  285. goto fin;
  286. result = safe_read(connection, &rec_error_code, sizeof(int));
  287. if (result != 0)
  288. goto fin;
  289. if (rec_error_code != 0) {
  290. error_code = rec_error_code;
  291. goto fin;
  292. }
  293. result = safe_read(connection, &result_size, sizeof(size_t));
  294. if (result != 0)
  295. goto fin;
  296. if (result_size > *data_size) {
  297. *data_size = result_size;
  298. error_code = -2;
  299. goto fin;
  300. }
  301. result = safe_read(connection, data, result_size);
  302. if (result != 0)
  303. goto fin;
  304. *data_size = result_size;
  305. error_code = 0;
  306. fin:
  307. return (error_code);
  308. }
  309. /*
  310. * Initializes the mp_write_session. For such a session the new connection
  311. * would be opened. The data should be written to the session with
  312. * __cached_mp_write function. The __close_cached_mp_write_session function
  313. * should be used to submit session and __abandon_cached_mp_write_session - to
  314. * abandon it. When the session is submitted, the whole se
  315. */
  316. struct cached_connection_ *
  317. __open_cached_mp_write_session(struct cached_connection_params const *params,
  318. const char *entry_name)
  319. {
  320. struct cached_connection_ *connection, *retval;
  321. size_t name_size;
  322. int error_code;
  323. int result;
  324. retval = NULL;
  325. connection = __open_cached_connection(params);
  326. if (connection == NULL)
  327. return (NULL);
  328. connection->mp_flag = 1;
  329. result = send_credentials(connection, CET_MP_WRITE_SESSION_REQUEST);
  330. if (result != 0)
  331. goto fin;
  332. name_size = strlen(entry_name);
  333. result = safe_write(connection, &name_size, sizeof(size_t));
  334. if (result != 0)
  335. goto fin;
  336. result = safe_write(connection, entry_name, name_size);
  337. if (result != 0)
  338. goto fin;
  339. result = safe_read(connection, &error_code, sizeof(int));
  340. if (result != 0)
  341. goto fin;
  342. if (error_code != 0)
  343. result = error_code;
  344. fin:
  345. if (result != 0)
  346. __close_cached_connection(connection);
  347. else
  348. retval = connection;
  349. return (retval);
  350. }
  351. /*
  352. * Adds new portion of data to the opened write session
  353. */
  354. int
  355. __cached_mp_write(struct cached_connection_ *ws, const char *data,
  356. size_t data_size)
  357. {
  358. int request, result;
  359. int error_code;
  360. error_code = -1;
  361. request = CET_MP_WRITE_SESSION_WRITE_REQUEST;
  362. result = safe_write(ws, &request, sizeof(int));
  363. if (result != 0)
  364. goto fin;
  365. result = safe_write(ws, &data_size, sizeof(size_t));
  366. if (result != 0)
  367. goto fin;
  368. result = safe_write(ws, data, data_size);
  369. if (result != 0)
  370. goto fin;
  371. result = safe_read(ws, &error_code, sizeof(int));
  372. if (result != 0)
  373. error_code = -1;
  374. fin:
  375. return (error_code);
  376. }
  377. /*
  378. * Abandons all operations with the write session. All data, that were written
  379. * to the session before, are discarded.
  380. */
  381. int
  382. __abandon_cached_mp_write_session(struct cached_connection_ *ws)
  383. {
  384. int notification;
  385. int result;
  386. notification = CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION;
  387. result = safe_write(ws, &notification, sizeof(int));
  388. __close_cached_connection(ws);
  389. return (result);
  390. }
  391. /*
  392. * Gracefully closes the write session. The data, that were previously written
  393. * to the session, are committed.
  394. */
  395. int
  396. __close_cached_mp_write_session(struct cached_connection_ *ws)
  397. {
  398. int notification;
  399. int result;
  400. notification = CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION;
  401. result = safe_write(ws, &notification, sizeof(int));
  402. __close_cached_connection(ws);
  403. return (0);
  404. }
  405. struct cached_connection_ *
  406. __open_cached_mp_read_session(struct cached_connection_params const *params,
  407. const char *entry_name)
  408. {
  409. struct cached_connection_ *connection, *retval;
  410. size_t name_size;
  411. int error_code;
  412. int result;
  413. retval = NULL;
  414. connection = __open_cached_connection(params);
  415. if (connection == NULL)
  416. return (NULL);
  417. connection->mp_flag = 1;
  418. result = send_credentials(connection, CET_MP_READ_SESSION_REQUEST);
  419. if (result != 0)
  420. goto fin;
  421. name_size = strlen(entry_name);
  422. result = safe_write(connection, &name_size, sizeof(size_t));
  423. if (result != 0)
  424. goto fin;
  425. result = safe_write(connection, entry_name, name_size);
  426. if (result != 0)
  427. goto fin;
  428. result = safe_read(connection, &error_code, sizeof(int));
  429. if (result != 0)
  430. goto fin;
  431. if (error_code != 0)
  432. result = error_code;
  433. fin:
  434. if (result != 0)
  435. __close_cached_connection(connection);
  436. else
  437. retval = connection;
  438. return (retval);
  439. }
  440. int
  441. __cached_mp_read(struct cached_connection_ *rs, char *data, size_t *data_size)
  442. {
  443. size_t result_size;
  444. int error_code, rec_error_code;
  445. int request, result;
  446. error_code = -1;
  447. request = CET_MP_READ_SESSION_READ_REQUEST;
  448. result = safe_write(rs, &request, sizeof(int));
  449. if (result != 0)
  450. goto fin;
  451. result = safe_read(rs, &rec_error_code, sizeof(int));
  452. if (result != 0)
  453. goto fin;
  454. if (rec_error_code != 0) {
  455. error_code = rec_error_code;
  456. goto fin;
  457. }
  458. result = safe_read(rs, &result_size, sizeof(size_t));
  459. if (result != 0)
  460. goto fin;
  461. if (result_size > *data_size) {
  462. *data_size = result_size;
  463. error_code = -2;
  464. goto fin;
  465. }
  466. result = safe_read(rs, data, result_size);
  467. if (result != 0)
  468. goto fin;
  469. *data_size = result_size;
  470. error_code = 0;
  471. fin:
  472. return (error_code);
  473. }
  474. int
  475. __close_cached_mp_read_session(struct cached_connection_ *rs)
  476. {
  477. __close_cached_connection(rs);
  478. return (0);
  479. }