/example/ofp_netwrap_crt/netwrap_socket.c

https://github.com/OpenFastPath/ofp · C · 676 lines · 542 code · 105 blank · 29 comment · 119 complexity · a8b7ed2d0a37140754b94f7bab2b6e8a MD5 · raw file

  1. /* Copyright (c) 2016, ENEA Software AB
  2. * Copyright (c) 2016, Nokia
  3. * All rights reserved.
  4. *
  5. * SPDX-License-Identifier: BSD-3-Clause
  6. */
  7. #include "netwrap_common.h"
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <strings.h>
  11. #include <ifaddrs.h>
  12. #include <arpa/inet.h>
  13. #include <sys/types.h>
  14. #include <sys/socket.h>
  15. #include <netinet/in.h>
  16. #include <netinet/tcp.h>
  17. #include <unistd.h>
  18. #include "ofp.h"
  19. #include "netwrap_socket.h"
  20. #include "netwrap_errno.h"
  21. union _ofp_sockaddr_storage {
  22. struct ofp_sockaddr_in addr_in;
  23. struct ofp_sockaddr_in6 addr_in6;
  24. };
  25. static int setup_socket_wrappers_called;
  26. static int (*libc_socket)(int, int, int);
  27. static int (*libc_shutdown)(int, int);
  28. static int (*libc_close)(int);
  29. static int (*libc_bind)(int, const struct sockaddr*, socklen_t);
  30. static int (*libc_accept)(int, struct sockaddr*, socklen_t*);
  31. static int (*libc_accept4)(int, struct sockaddr*, socklen_t*, int);
  32. static int (*libc_listen)(int, int);
  33. static int (*libc_connect)(int, const struct sockaddr*, socklen_t);
  34. static ssize_t (*libc_read)(int, void*, size_t);
  35. static ssize_t (*libc_write)(int, const void*, size_t);
  36. static ssize_t (*libc_recv)(int, void*, size_t, int);
  37. static ssize_t (*libc_send)(int, const void*, size_t, int);
  38. void setup_socket_wrappers(void)
  39. {
  40. LIBC_FUNCTION(socket);
  41. LIBC_FUNCTION(shutdown);
  42. LIBC_FUNCTION(close);
  43. LIBC_FUNCTION(bind);
  44. LIBC_FUNCTION(accept);
  45. LIBC_FUNCTION(accept4);
  46. LIBC_FUNCTION(listen);
  47. LIBC_FUNCTION(connect);
  48. LIBC_FUNCTION(read);
  49. LIBC_FUNCTION(write);
  50. LIBC_FUNCTION(recv);
  51. LIBC_FUNCTION(send);
  52. setup_socket_wrappers_called = 1;
  53. }
  54. int socket(int domain, int type, int protocol)
  55. {
  56. int sockfd = -1;
  57. if (setup_socket_wrappers_called) {
  58. if (domain != AF_INET)
  59. sockfd = (*libc_socket)(domain, type, protocol);
  60. else {
  61. int ofp_domain = OFP_AF_INET;
  62. int ofp_type, ofp_protocol;
  63. switch (type) {
  64. case SOCK_STREAM:
  65. ofp_type = OFP_SOCK_STREAM;
  66. break;
  67. case SOCK_DGRAM:
  68. ofp_type = OFP_SOCK_DGRAM;
  69. break;
  70. default:
  71. ofp_type = type;
  72. }
  73. switch (protocol) {
  74. case IPPROTO_UDP:
  75. ofp_protocol = OFP_IPPROTO_UDP;
  76. break;
  77. case IPPROTO_TCP:
  78. ofp_protocol = OFP_IPPROTO_TCP;
  79. break;
  80. default:
  81. ofp_protocol = protocol;
  82. }
  83. sockfd = ofp_socket(ofp_domain, ofp_type, ofp_protocol);
  84. errno = NETWRAP_ERRNO(ofp_errno);
  85. }
  86. } else { /* pre init*/
  87. LIBC_FUNCTION(socket);
  88. if (libc_socket)
  89. sockfd = (*libc_socket)(domain, type, protocol);
  90. else {
  91. sockfd = -1;
  92. errno = EACCES;
  93. }
  94. }
  95. /*printf("socket wrapper return: %d\n", sockfd);*/
  96. return sockfd;
  97. }
  98. int shutdown(int sockfd, int how)
  99. {
  100. int shutdown_value;
  101. if (IS_OFP_SOCKET(sockfd)) {
  102. int ofp_how;
  103. switch (how) {
  104. case SHUT_RD:
  105. ofp_how = OFP_SHUT_RD;
  106. break;
  107. case SHUT_WR:
  108. ofp_how = OFP_SHUT_WR;
  109. break;
  110. case SHUT_RDWR:
  111. ofp_how = OFP_SHUT_RDWR;
  112. break;
  113. default:
  114. ofp_how = how;
  115. }
  116. shutdown_value = ofp_shutdown(sockfd, ofp_how);
  117. errno = NETWRAP_ERRNO(ofp_errno);
  118. } else if (libc_shutdown) {
  119. shutdown_value = (*libc_shutdown)(sockfd, how);
  120. } else {
  121. LIBC_FUNCTION(shutdown);
  122. if (libc_shutdown)
  123. shutdown_value = (*libc_shutdown)(sockfd, how);
  124. else {
  125. shutdown_value = -1;
  126. errno = EACCES;
  127. }
  128. }
  129. return shutdown_value;
  130. }
  131. int close(int sockfd)
  132. {
  133. int close_value;
  134. if (IS_OFP_SOCKET(sockfd)) {
  135. close_value = ofp_close(sockfd);
  136. errno = NETWRAP_ERRNO(ofp_errno);
  137. } else if (libc_close)
  138. close_value = (*libc_close)(sockfd);
  139. else { /* pre init*/
  140. LIBC_FUNCTION(close);
  141. if (libc_close)
  142. close_value = (*libc_close)(sockfd);
  143. else {
  144. close_value = -1;
  145. errno = EACCES;
  146. }
  147. }
  148. /*printf("Socket '%d' closed returns:'%d'\n",
  149. sockfd, close_value);*/
  150. return close_value;
  151. }
  152. int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
  153. {
  154. int bind_value = -1;
  155. if (IS_OFP_SOCKET(sockfd)) {
  156. struct ofp_sockaddr_in ofp_addr;
  157. ofp_socklen_t ofp_addrlen;
  158. if (!addr) {
  159. errno = EFAULT;
  160. return -1;
  161. }
  162. if (addrlen != sizeof(struct sockaddr_in)) {
  163. errno = EINVAL;
  164. return -1;
  165. }
  166. bzero((char *) &ofp_addr, sizeof(ofp_addr));
  167. ofp_addr.sin_family = OFP_AF_INET;
  168. ofp_addr.sin_addr.s_addr =
  169. ((const struct sockaddr_in *)addr)->sin_addr.s_addr;
  170. ofp_addr.sin_port =
  171. ((const struct sockaddr_in *)addr)->sin_port;
  172. ofp_addr.sin_len = sizeof(struct ofp_sockaddr_in);
  173. ofp_addrlen = sizeof(ofp_addr);
  174. bind_value = ofp_bind(sockfd,
  175. (const struct ofp_sockaddr *)&ofp_addr,
  176. ofp_addrlen);
  177. errno = NETWRAP_ERRNO(ofp_errno);
  178. } else if (libc_bind)
  179. bind_value = (*libc_bind)(sockfd, addr, addrlen);
  180. else { /* pre init*/
  181. LIBC_FUNCTION(bind);
  182. if (libc_bind)
  183. bind_value = (*libc_bind)(sockfd, addr, addrlen);
  184. else {
  185. bind_value = -1;
  186. errno = EACCES;
  187. }
  188. }
  189. /*printf("Binding socket '%d' to the address '%x:%d' returns:%d\n",
  190. sockfd, ((const struct sockaddr_in *)addr)->sin_addr.s_addr,
  191. odp_be_to_cpu_16(((const struct sockaddr_in *)addr)->sin_port),
  192. bind_value);*/
  193. return bind_value;
  194. }
  195. int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
  196. {
  197. int accept_value = -1;
  198. if (IS_OFP_SOCKET(sockfd)) {
  199. union _ofp_sockaddr_storage ofp_addr_local;
  200. struct ofp_sockaddr *ofp_addr;
  201. ofp_socklen_t ofp_addrlen_local;
  202. ofp_socklen_t *ofp_addrlen;
  203. if (addr) {
  204. ofp_addr = (struct ofp_sockaddr *)&ofp_addr_local;
  205. if (!addrlen) {
  206. errno = EINVAL;
  207. return -1;
  208. }
  209. ofp_addrlen = &ofp_addrlen_local;
  210. ofp_addrlen_local = sizeof(ofp_addr_local);
  211. } else {
  212. ofp_addr = NULL;
  213. ofp_addrlen = NULL;
  214. }
  215. accept_value = ofp_accept(sockfd, ofp_addr, ofp_addrlen);
  216. errno = NETWRAP_ERRNO(ofp_errno);
  217. if (accept_value != -1 && addr) {
  218. switch (ofp_addr->sa_family) {
  219. case OFP_AF_INET:
  220. {
  221. struct sockaddr_in addr_in_tmp;
  222. struct ofp_sockaddr_in *ofp_addr_in_tmp =
  223. (struct ofp_sockaddr_in *)ofp_addr;
  224. addr_in_tmp.sin_family = AF_INET;
  225. addr_in_tmp.sin_port =
  226. ofp_addr_in_tmp->sin_port;
  227. addr_in_tmp.sin_addr.s_addr =
  228. ofp_addr_in_tmp->sin_addr.s_addr;
  229. if (*addrlen > sizeof(addr_in_tmp))
  230. *addrlen = sizeof(addr_in_tmp);
  231. memcpy(addr, &addr_in_tmp, *addrlen);
  232. break;
  233. }
  234. case OFP_AF_INET6:
  235. {
  236. struct sockaddr_in6 addr_in6_tmp;
  237. struct ofp_sockaddr_in6 *ofp_addr_in6_tmp =
  238. (struct ofp_sockaddr_in6 *)ofp_addr;
  239. addr_in6_tmp.sin6_family = AF_INET6;
  240. addr_in6_tmp.sin6_port =
  241. ofp_addr_in6_tmp->sin6_port;
  242. addr_in6_tmp.sin6_flowinfo =
  243. ofp_addr_in6_tmp->sin6_flowinfo;
  244. addr_in6_tmp.sin6_scope_id =
  245. ofp_addr_in6_tmp->sin6_scope_id;
  246. memcpy((unsigned char *)addr_in6_tmp.sin6_addr.s6_addr,
  247. (unsigned char *)ofp_addr_in6_tmp->sin6_addr.__u6_addr.__u6_addr16,
  248. 16);
  249. if (*addrlen > sizeof(addr_in6_tmp))
  250. *addrlen = sizeof(addr_in6_tmp);
  251. memcpy(addr, &addr_in6_tmp, *addrlen);
  252. break;
  253. }
  254. default:
  255. return -1;
  256. }
  257. }
  258. } else if (libc_accept)
  259. accept_value = (*libc_accept)(sockfd, addr, addrlen);
  260. else { /* pre init*/
  261. LIBC_FUNCTION(accept);
  262. if (libc_accept)
  263. accept_value = (*libc_accept)(sockfd, addr, addrlen);
  264. else {
  265. accept_value = -1;
  266. errno = EACCES;
  267. }
  268. }
  269. /*printf("Accept called on socket '%d' returned:'%d'\n",
  270. sockfd, accept_value);*/
  271. return accept_value;
  272. }
  273. int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
  274. {
  275. int accept_value = -1;
  276. if (IS_OFP_SOCKET(sockfd)) {
  277. union _ofp_sockaddr_storage ofp_addr_local;
  278. struct ofp_sockaddr *ofp_addr;
  279. ofp_socklen_t ofp_addrlen_local;
  280. ofp_socklen_t *ofp_addrlen;
  281. if (addr) {
  282. ofp_addr = (struct ofp_sockaddr *)&ofp_addr_local;
  283. if (!addrlen) {
  284. errno = EINVAL;
  285. return -1;
  286. }
  287. ofp_addrlen = &ofp_addrlen_local;
  288. ofp_addrlen_local = sizeof(ofp_addr_local);
  289. } else {
  290. ofp_addr = NULL;
  291. ofp_addrlen = NULL;
  292. }
  293. accept_value = ofp_accept(sockfd, ofp_addr, ofp_addrlen);
  294. errno = NETWRAP_ERRNO(ofp_errno);
  295. if (accept_value != -1 && addr) {
  296. switch (ofp_addr->sa_family) {
  297. case OFP_AF_INET:
  298. {
  299. struct sockaddr_in addr_in_tmp;
  300. struct ofp_sockaddr_in *ofp_addr_in_tmp =
  301. (struct ofp_sockaddr_in *)ofp_addr;
  302. addr_in_tmp.sin_family = AF_INET;
  303. addr_in_tmp.sin_port =
  304. ofp_addr_in_tmp->sin_port;
  305. addr_in_tmp.sin_addr.s_addr =
  306. ofp_addr_in_tmp->sin_addr.s_addr;
  307. if (*addrlen > sizeof(addr_in_tmp))
  308. *addrlen = sizeof(addr_in_tmp);
  309. memcpy(addr, &addr_in_tmp, *addrlen);
  310. break;
  311. }
  312. case OFP_AF_INET6:
  313. {
  314. struct sockaddr_in6 addr_in6_tmp;
  315. struct ofp_sockaddr_in6 *ofp_addr_in6_tmp =
  316. (struct ofp_sockaddr_in6 *)ofp_addr;
  317. addr_in6_tmp.sin6_family = AF_INET6;
  318. addr_in6_tmp.sin6_port =
  319. ofp_addr_in6_tmp->sin6_port;
  320. addr_in6_tmp.sin6_flowinfo =
  321. ofp_addr_in6_tmp->sin6_flowinfo;
  322. addr_in6_tmp.sin6_scope_id =
  323. ofp_addr_in6_tmp->sin6_scope_id;
  324. memcpy((unsigned char *)addr_in6_tmp.sin6_addr.s6_addr,
  325. (unsigned char *)ofp_addr_in6_tmp->sin6_addr.__u6_addr.__u6_addr16,
  326. 16);
  327. if (*addrlen > sizeof(addr_in6_tmp))
  328. *addrlen = sizeof(addr_in6_tmp);
  329. memcpy(addr, &addr_in6_tmp, *addrlen);
  330. break;
  331. }
  332. default:
  333. return -1;
  334. }
  335. }
  336. if ((accept_value != -1) && (flags & SOCK_NONBLOCK)) {
  337. int p = 1;
  338. if (ofp_ioctl(accept_value, OFP_FIONBIO, &p)) {
  339. errno = NETWRAP_ERRNO(ofp_errno);
  340. ofp_close(accept_value);
  341. accept_value = -1;
  342. }
  343. }
  344. } else if (libc_accept4)
  345. accept_value = (*libc_accept4)(sockfd, addr, addrlen, flags);
  346. else { /* pre init*/
  347. LIBC_FUNCTION(accept4);
  348. if (libc_accept4)
  349. accept_value = (*libc_accept4)(sockfd, addr,
  350. addrlen, flags);
  351. else {
  352. accept_value = -1;
  353. errno = EACCES;
  354. }
  355. }
  356. /*printf("Accept4 called on socket '%d' returned:'%d'\n",
  357. sockfd, accept_value);*/
  358. return accept_value;
  359. }
  360. int listen(int sockfd, int backlog)
  361. {
  362. int listen_value = -1;
  363. if (IS_OFP_SOCKET(sockfd)) {
  364. listen_value = ofp_listen(sockfd, backlog);
  365. errno = NETWRAP_ERRNO(ofp_errno);
  366. } else if (libc_listen)
  367. listen_value = (*libc_listen)(sockfd, backlog);
  368. else { /* pre init*/
  369. LIBC_FUNCTION(listen);
  370. if (libc_listen)
  371. listen_value = (*libc_listen)(sockfd, backlog);
  372. else {
  373. listen_value = -1;
  374. errno = EACCES;
  375. }
  376. }
  377. /*printf("Listen called on socket '%d' returns:'%d'\n",
  378. sockfd, listen_value);*/
  379. return listen_value;
  380. }
  381. int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
  382. {
  383. int connect_value;
  384. if (IS_OFP_SOCKET(sockfd)) {
  385. union _ofp_sockaddr_storage ofp_addr_local;
  386. struct ofp_sockaddr *ofp_addr;
  387. ofp_socklen_t ofp_addrlen;
  388. if (!addr || addrlen < sizeof(short)) {
  389. errno = EINVAL;
  390. return -1;
  391. }
  392. ofp_addr = (struct ofp_sockaddr *)&ofp_addr_local;
  393. switch (addr->sa_family) {
  394. case AF_INET:
  395. {
  396. const struct sockaddr_in *addr_in_tmp;
  397. struct ofp_sockaddr_in *ofp_addr_in_tmp;
  398. if (addrlen < sizeof(struct sockaddr_in)) {
  399. errno = EINVAL;
  400. return -1;
  401. }
  402. addr_in_tmp = (const struct sockaddr_in *)addr;
  403. ofp_addr_in_tmp = (struct ofp_sockaddr_in *)ofp_addr;
  404. ofp_addr_in_tmp->sin_family = OFP_AF_INET;
  405. ofp_addr_in_tmp->sin_port = addr_in_tmp->sin_port;
  406. ofp_addr_in_tmp->sin_len =
  407. sizeof(struct ofp_sockaddr_in);
  408. ofp_addr_in_tmp->sin_addr.s_addr =
  409. addr_in_tmp->sin_addr.s_addr;
  410. ofp_addrlen = sizeof(struct ofp_sockaddr_in);
  411. break;
  412. }
  413. case AF_INET6:
  414. {
  415. const struct sockaddr_in6 *addr_in6_tmp;
  416. struct ofp_sockaddr_in6 *ofp_addr_in6_tmp;
  417. if (addrlen < sizeof(struct sockaddr_in6)) {
  418. errno = EINVAL;
  419. return -1;
  420. }
  421. addr_in6_tmp = (const struct sockaddr_in6 *)addr;
  422. ofp_addr_in6_tmp = (struct ofp_sockaddr_in6 *)ofp_addr;
  423. ofp_addr_in6_tmp->sin6_family = OFP_AF_INET6;
  424. ofp_addr_in6_tmp->sin6_port = addr_in6_tmp->sin6_port;
  425. ofp_addr_in6_tmp->sin6_flowinfo =
  426. addr_in6_tmp->sin6_flowinfo;
  427. ofp_addr_in6_tmp->sin6_scope_id =
  428. addr_in6_tmp->sin6_scope_id;
  429. ofp_addr_in6_tmp->sin6_len =
  430. sizeof(struct ofp_sockaddr_in6);
  431. memcpy((unsigned char *)ofp_addr_in6_tmp->sin6_addr.__u6_addr.__u6_addr16,
  432. (const unsigned char *)addr_in6_tmp->sin6_addr.s6_addr,
  433. 16);
  434. ofp_addrlen = sizeof(struct ofp_sockaddr_in6);
  435. break;
  436. }
  437. default:
  438. errno = EAFNOSUPPORT;
  439. return -1;
  440. };
  441. connect_value = ofp_connect(sockfd,
  442. ofp_addr,
  443. ofp_addrlen);
  444. errno = NETWRAP_ERRNO(ofp_errno);
  445. } else if (libc_connect)
  446. connect_value = (*libc_connect)(sockfd, addr, addrlen);
  447. else {
  448. LIBC_FUNCTION(connect);
  449. if (libc_connect)
  450. connect_value = (*libc_connect)(sockfd, addr, addrlen);
  451. else {
  452. connect_value = -1;
  453. errno = EACCES;
  454. }
  455. }
  456. /*printf("Connect called on socket '%d' returns:'%d'\n",
  457. sockfd, connect_value);*/
  458. return connect_value;
  459. }
  460. ssize_t read(int sockfd, void *buf, size_t len)
  461. {
  462. ssize_t read_value;
  463. if (IS_OFP_SOCKET(sockfd)) {
  464. read_value = ofp_recv(sockfd, buf, len, 0);
  465. errno = NETWRAP_ERRNO(ofp_errno);
  466. } else if (libc_read)
  467. read_value = (*libc_read)(sockfd, buf, len);
  468. else {
  469. LIBC_FUNCTION(read);
  470. if (libc_read)
  471. read_value = (*libc_read)(sockfd, buf, len);
  472. else {
  473. read_value = -1;
  474. errno = EACCES;
  475. }
  476. }
  477. return read_value;
  478. }
  479. ssize_t write(int sockfd, const void *buf, size_t len)
  480. {
  481. ssize_t write_value;
  482. if (IS_OFP_SOCKET(sockfd)) {
  483. write_value = ofp_send(sockfd, buf, len, 0);
  484. errno = NETWRAP_ERRNO(ofp_errno);
  485. } else if (libc_write)
  486. write_value = (*libc_write)(sockfd, buf, len);
  487. else {
  488. LIBC_FUNCTION(write);
  489. if (libc_write)
  490. write_value = (*libc_write)(sockfd, buf, len);
  491. else {
  492. write_value = -1;
  493. errno = EACCES;
  494. }
  495. }
  496. return write_value;
  497. }
  498. ssize_t recv(int sockfd, void *buf, size_t len, int flags)
  499. {
  500. ssize_t recv_value;
  501. if (IS_OFP_SOCKET(sockfd)) {
  502. int ofp_flags = 0;
  503. if (flags) {
  504. /*if (flags & MSG_CMSG_CLOEXEC)
  505. ofp_flags |= MSG_CMSG_CLOEXEC;*/
  506. if (flags & MSG_DONTWAIT)
  507. ofp_flags |= OFP_MSG_DONTWAIT;
  508. /*if (flags & MSG_ERRQUEUE)
  509. ofp_flags |= MSG_ERRQUEUE;*/
  510. if (flags & MSG_OOB)
  511. ofp_flags |= OFP_MSG_OOB;
  512. if (flags & MSG_PEEK)
  513. ofp_flags |= OFP_MSG_PEEK;
  514. if (flags & MSG_TRUNC)
  515. ofp_flags |= OFP_MSG_TRUNC;
  516. if (flags & MSG_WAITALL)
  517. ofp_flags |= OFP_MSG_WAITALL;
  518. }
  519. recv_value = ofp_recv(sockfd, buf, len, ofp_flags);
  520. errno = NETWRAP_ERRNO(ofp_errno);
  521. } else if (libc_recv)
  522. recv_value = (*libc_recv)(sockfd, buf, len, flags);
  523. else { /* pre init*/
  524. LIBC_FUNCTION(recv);
  525. if (libc_recv)
  526. recv_value = (*libc_recv)(sockfd, buf, len, flags);
  527. else {
  528. recv_value = -1;
  529. errno = EACCES;
  530. }
  531. }
  532. return recv_value;
  533. }
  534. ssize_t send(int sockfd, const void *buf, size_t len, int flags)
  535. {
  536. ssize_t send_value;
  537. if (IS_OFP_SOCKET(sockfd)) {
  538. int ofp_flags = 0;
  539. if (flags) {
  540. /*if (flags & MSG_CONFIRM)
  541. ofp_flags |= OFP_MSG_CONFIRM;*/
  542. if (flags & MSG_DONTROUTE)
  543. ofp_flags |= OFP_MSG_DONTROUTE;
  544. if (flags & MSG_DONTWAIT)
  545. ofp_flags |= OFP_MSG_DONTWAIT;
  546. if (flags & MSG_DONTWAIT)
  547. ofp_flags |= OFP_MSG_DONTWAIT;
  548. if (flags & MSG_EOR)
  549. ofp_flags |= OFP_MSG_EOR;
  550. /*if (flags & MSG_MORE)
  551. ofp_flags |= OFP_MSG_MORE;*/
  552. if (flags & MSG_NOSIGNAL)
  553. ofp_flags |= OFP_MSG_NOSIGNAL;
  554. if (flags & MSG_OOB)
  555. ofp_flags |= OFP_MSG_OOB;
  556. }
  557. send_value = ofp_send(sockfd, buf, len, ofp_flags);
  558. errno = NETWRAP_ERRNO(ofp_errno);
  559. } else if (libc_send)
  560. send_value = (*libc_send)(sockfd, buf, len, flags);
  561. else {
  562. LIBC_FUNCTION(send);
  563. if (libc_send)
  564. send_value = (*libc_send)(sockfd, buf, len, flags);
  565. else {
  566. send_value = -1;
  567. errno = EACCES;
  568. }
  569. }
  570. return send_value;
  571. }