PageRenderTime 52ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/src/google/protobuf-c/protobuf-c-rpc.c

http://protobuf-c.googlecode.com/
C | 1511 lines | 1293 code | 126 blank | 92 comment | 158 complexity | 7c659d149a71783f04d8fd443dc7def9 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /* KNOWN DEFECTS:
  2. - server does not obey max_pending_requests_per_connection
  3. - no ipv6 support
  4. */
  5. #include <string.h>
  6. #include <assert.h>
  7. #include <sys/stat.h>
  8. #include <sys/types.h>
  9. #include <sys/socket.h>
  10. #include <sys/un.h>
  11. #include <netinet/in.h>
  12. #include <netdb.h>
  13. #include <stdarg.h>
  14. #include <fcntl.h>
  15. #include <errno.h>
  16. #include <netinet/in.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include "protobuf-c-rpc.h"
  21. #include "protobuf-c-data-buffer.h"
  22. #include "gsklistmacros.h"
  23. #define protobuf_c_assert(x) assert(x)
  24. #undef TRUE
  25. #define TRUE 1
  26. #undef FALSE
  27. #define FALSE 0
  28. /* enabled for efficiency, can be useful to disable for debugging */
  29. #define RECYCLE_REQUESTS 1
  30. #define UINT_TO_POINTER(ui) ((void*)(uintptr_t)(ui))
  31. #define POINTER_TO_UINT(ptr) ((unsigned)(uintptr_t)(ptr))
  32. #define MAX_FAILED_MSG_LENGTH 512
  33. typedef enum
  34. {
  35. PROTOBUF_C_CLIENT_STATE_INIT,
  36. PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP,
  37. PROTOBUF_C_CLIENT_STATE_CONNECTING,
  38. PROTOBUF_C_CLIENT_STATE_CONNECTED,
  39. PROTOBUF_C_CLIENT_STATE_FAILED_WAITING,
  40. PROTOBUF_C_CLIENT_STATE_FAILED, /* if no autoreconnect */
  41. PROTOBUF_C_CLIENT_STATE_DESTROYED
  42. } ProtobufC_RPC_ClientState;
  43. typedef struct _Closure Closure;
  44. struct _Closure
  45. {
  46. /* these will be NULL for unallocated request ids */
  47. const ProtobufCMessageDescriptor *response_type;
  48. ProtobufCClosure closure;
  49. /* this is the next request id, or 0 for none */
  50. void *closure_data;
  51. };
  52. static void
  53. error_handler (ProtobufC_RPC_Error_Code code,
  54. const char *message,
  55. void *error_func_data)
  56. {
  57. fprintf (stderr, "*** error: %s: %s\n",
  58. (char*) error_func_data, message);
  59. }
  60. struct _ProtobufC_RPC_Client
  61. {
  62. ProtobufCService base_service;
  63. ProtobufCDataBuffer incoming;
  64. ProtobufCDataBuffer outgoing;
  65. ProtobufCAllocator *allocator;
  66. ProtobufCDispatch *dispatch;
  67. ProtobufC_RPC_AddressType address_type;
  68. char *name;
  69. ProtobufC_FD fd;
  70. protobuf_c_boolean autoreconnect;
  71. unsigned autoreconnect_millis;
  72. ProtobufC_NameLookup_Func resolver;
  73. ProtobufC_RPC_Error_Func error_handler;
  74. void *error_handler_data;
  75. ProtobufC_RPC_ClientState state;
  76. union {
  77. struct {
  78. ProtobufCDispatchIdle *idle;
  79. } init;
  80. struct {
  81. protobuf_c_boolean pending;
  82. protobuf_c_boolean destroyed_while_pending;
  83. uint16_t port;
  84. } name_lookup;
  85. struct {
  86. unsigned closures_alloced;
  87. unsigned first_free_request_id;
  88. /* indexed by (request_id-1) */
  89. Closure *closures;
  90. } connected;
  91. struct {
  92. ProtobufCDispatchTimer *timer;
  93. char *error_message;
  94. } failed_waiting;
  95. struct {
  96. char *error_message;
  97. } failed;
  98. } info;
  99. };
  100. static void begin_name_lookup (ProtobufC_RPC_Client *client);
  101. static void destroy_client_rpc (ProtobufCService *service);
  102. static void
  103. set_fd_nonblocking(int fd)
  104. {
  105. int flags = fcntl (fd, F_GETFL);
  106. protobuf_c_assert (flags >= 0);
  107. fcntl (fd, F_SETFL, flags | O_NONBLOCK);
  108. }
  109. static void
  110. handle_autoreconnect_timeout (ProtobufCDispatch *dispatch,
  111. void *func_data)
  112. {
  113. ProtobufC_RPC_Client *client = func_data;
  114. protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_FAILED_WAITING);
  115. client->allocator->free (client->allocator,
  116. client->info.failed_waiting.error_message);
  117. begin_name_lookup (client);
  118. }
  119. static void
  120. client_failed (ProtobufC_RPC_Client *client,
  121. const char *format_str,
  122. ...)
  123. {
  124. va_list args;
  125. char buf[MAX_FAILED_MSG_LENGTH];
  126. size_t msg_len;
  127. char *msg;
  128. size_t n_closures = 0;
  129. Closure *closures = NULL;
  130. switch (client->state)
  131. {
  132. case PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP:
  133. protobuf_c_assert (!client->info.name_lookup.pending);
  134. break;
  135. case PROTOBUF_C_CLIENT_STATE_CONNECTING:
  136. /* nothing to do */
  137. break;
  138. case PROTOBUF_C_CLIENT_STATE_CONNECTED:
  139. n_closures = client->info.connected.closures_alloced;
  140. closures = client->info.connected.closures;
  141. break;
  142. /* should not get here */
  143. case PROTOBUF_C_CLIENT_STATE_INIT:
  144. case PROTOBUF_C_CLIENT_STATE_FAILED_WAITING:
  145. case PROTOBUF_C_CLIENT_STATE_FAILED:
  146. case PROTOBUF_C_CLIENT_STATE_DESTROYED:
  147. protobuf_c_assert (FALSE);
  148. break;
  149. }
  150. if (client->fd >= 0)
  151. {
  152. protobuf_c_dispatch_close_fd (client->dispatch, client->fd);
  153. client->fd = -1;
  154. }
  155. protobuf_c_data_buffer_reset (&client->incoming);
  156. protobuf_c_data_buffer_reset (&client->outgoing);
  157. /* Compute the message */
  158. va_start (args, format_str);
  159. vsnprintf (buf, sizeof (buf), format_str, args);
  160. va_end (args);
  161. buf[sizeof(buf)-1] = 0;
  162. msg_len = strlen (buf);
  163. msg = client->allocator->alloc (client->allocator, msg_len + 1);
  164. strcpy (msg, buf);
  165. /* go to one of the failed states */
  166. if (client->autoreconnect)
  167. {
  168. client->state = PROTOBUF_C_CLIENT_STATE_FAILED_WAITING;
  169. client->info.failed_waiting.timer
  170. = protobuf_c_dispatch_add_timer_millis (client->dispatch,
  171. client->autoreconnect_millis,
  172. handle_autoreconnect_timeout,
  173. client);
  174. client->info.failed_waiting.error_message = msg;
  175. }
  176. else
  177. {
  178. client->state = PROTOBUF_C_CLIENT_STATE_FAILED;
  179. client->info.failed.error_message = msg;
  180. }
  181. /* we defer calling the closures to avoid
  182. any re-entrancy issues (e.g. people further RPC should
  183. not see a socket in the "connected" state-- at least,
  184. it shouldn't be accessing the array of closures that we are considering */
  185. if (closures != NULL)
  186. {
  187. unsigned i;
  188. for (i = 0; i < n_closures; i++)
  189. if (closures[i].response_type != NULL)
  190. closures[i].closure (NULL, closures[i].closure_data);
  191. client->allocator->free (client->allocator, closures);
  192. }
  193. }
  194. static inline protobuf_c_boolean
  195. errno_is_ignorable (int e)
  196. {
  197. #ifdef EWOULDBLOCK /* for windows */
  198. if (e == EWOULDBLOCK)
  199. return 1;
  200. #endif
  201. return e == EINTR || e == EAGAIN;
  202. }
  203. static void
  204. set_state_connected (ProtobufC_RPC_Client *client)
  205. {
  206. client->state = PROTOBUF_C_CLIENT_STATE_CONNECTED;
  207. client->info.connected.closures_alloced = 1;
  208. client->info.connected.first_free_request_id = 1;
  209. client->info.connected.closures = client->allocator->alloc (client->allocator, sizeof (Closure));
  210. client->info.connected.closures[0].closure = NULL;
  211. client->info.connected.closures[0].response_type = NULL;
  212. client->info.connected.closures[0].closure_data = UINT_TO_POINTER (0);
  213. }
  214. static void
  215. handle_client_fd_connect_events (int fd,
  216. unsigned events,
  217. void *callback_data)
  218. {
  219. ProtobufC_RPC_Client *client = callback_data;
  220. socklen_t size_int = sizeof (int);
  221. int fd_errno = EINVAL;
  222. if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &fd_errno, &size_int) < 0)
  223. {
  224. /* Note: this behavior is vaguely hypothetically broken,
  225. * in terms of ignoring getsockopt's error;
  226. * however, this shouldn't happen, and EINVAL is ok if it does.
  227. * Furthermore some broken OS's return an error code when
  228. * fetching SO_ERROR!
  229. */
  230. }
  231. if (fd_errno == 0)
  232. {
  233. /* goto state CONNECTED */
  234. protobuf_c_dispatch_watch_fd (client->dispatch,
  235. client->fd,
  236. 0, NULL, NULL);
  237. set_state_connected (client);
  238. }
  239. else if (errno_is_ignorable (fd_errno))
  240. {
  241. /* remain in CONNECTING state */
  242. return;
  243. }
  244. else
  245. {
  246. /* Call error handler */
  247. protobuf_c_dispatch_close_fd (client->dispatch, client->fd);
  248. client_failed (client,
  249. "failed connecting to server: %s",
  250. strerror (fd_errno));
  251. }
  252. }
  253. static void
  254. begin_connecting (ProtobufC_RPC_Client *client,
  255. struct sockaddr *address,
  256. size_t addr_len)
  257. {
  258. protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP);
  259. client->state = PROTOBUF_C_CLIENT_STATE_CONNECTING;
  260. client->fd = socket (address->sa_family, SOCK_STREAM, 0);
  261. if (client->fd < 0)
  262. {
  263. client_failed (client, "error creating socket: %s", strerror (errno));
  264. return;
  265. }
  266. set_fd_nonblocking (client->fd);
  267. if (connect (client->fd, address, addr_len) < 0)
  268. {
  269. if (errno == EINPROGRESS)
  270. {
  271. /* register interest in fd */
  272. protobuf_c_dispatch_watch_fd (client->dispatch,
  273. client->fd,
  274. PROTOBUF_C_EVENT_READABLE|PROTOBUF_C_EVENT_WRITABLE,
  275. handle_client_fd_connect_events,
  276. client);
  277. return;
  278. }
  279. close (client->fd);
  280. client->fd = -1;
  281. client_failed (client, "error connecting to remote host: %s", strerror (errno));
  282. return;
  283. }
  284. set_state_connected (client);
  285. }
  286. static void
  287. handle_name_lookup_success (const uint8_t *address,
  288. void *callback_data)
  289. {
  290. ProtobufC_RPC_Client *client = callback_data;
  291. struct sockaddr_in addr;
  292. protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP);
  293. protobuf_c_assert (client->info.name_lookup.pending);
  294. client->info.name_lookup.pending = 0;
  295. if (client->info.name_lookup.destroyed_while_pending)
  296. {
  297. destroy_client_rpc (&client->base_service);
  298. return;
  299. }
  300. memset (&addr, 0, sizeof (addr));
  301. addr.sin_family = AF_INET;
  302. memcpy (&addr.sin_addr, address, 4);
  303. addr.sin_port = htons (client->info.name_lookup.port);
  304. begin_connecting (client, (struct sockaddr *) &addr, sizeof (addr));
  305. }
  306. static void
  307. handle_name_lookup_failure (const char *error_message,
  308. void *callback_data)
  309. {
  310. ProtobufC_RPC_Client *client = callback_data;
  311. protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP);
  312. protobuf_c_assert (client->info.name_lookup.pending);
  313. client->info.name_lookup.pending = 0;
  314. if (client->info.name_lookup.destroyed_while_pending)
  315. {
  316. destroy_client_rpc (&client->base_service);
  317. return;
  318. }
  319. client_failed (client, "name lookup failed (for name from %s): %s", client->name, error_message);
  320. }
  321. static void
  322. begin_name_lookup (ProtobufC_RPC_Client *client)
  323. {
  324. protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_INIT
  325. || client->state == PROTOBUF_C_CLIENT_STATE_FAILED_WAITING
  326. || client->state == PROTOBUF_C_CLIENT_STATE_FAILED);
  327. client->state = PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP;
  328. client->info.name_lookup.pending = 0;
  329. switch (client->address_type)
  330. {
  331. case PROTOBUF_C_RPC_ADDRESS_LOCAL:
  332. {
  333. struct sockaddr_un addr;
  334. addr.sun_family = AF_UNIX;
  335. strncpy (addr.sun_path, client->name, sizeof (addr.sun_path));
  336. begin_connecting (client, (struct sockaddr *) &addr,
  337. sizeof (addr));
  338. return;
  339. }
  340. case PROTOBUF_C_RPC_ADDRESS_TCP:
  341. {
  342. /* parse hostname:port from client->name */
  343. const char *colon = strchr (client->name, ':');
  344. char *host;
  345. unsigned port;
  346. if (colon == NULL)
  347. {
  348. client_failed (client,
  349. "name '%s' does not have a : in it (supposed to be HOST:PORT)",
  350. client->name);
  351. return;
  352. }
  353. host = client->allocator->alloc (client->allocator, colon + 1 - client->name);
  354. memcpy (host, client->name, colon - client->name);
  355. host[colon - client->name] = 0;
  356. port = atoi (colon + 1);
  357. client->info.name_lookup.pending = 1;
  358. client->info.name_lookup.destroyed_while_pending = 0;
  359. client->info.name_lookup.port = port;
  360. client->resolver (client->dispatch,
  361. host,
  362. handle_name_lookup_success,
  363. handle_name_lookup_failure,
  364. client);
  365. /* cleanup */
  366. client->allocator->free (client->allocator, host);
  367. return;
  368. }
  369. default:
  370. assert (0);
  371. }
  372. }
  373. static void
  374. handle_init_idle (ProtobufCDispatch *dispatch,
  375. void *data)
  376. {
  377. ProtobufC_RPC_Client *client = data;
  378. protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_INIT);
  379. begin_name_lookup (client);
  380. }
  381. static void
  382. grow_closure_array (ProtobufC_RPC_Client *client)
  383. {
  384. /* resize array */
  385. unsigned old_size = client->info.connected.closures_alloced;
  386. unsigned new_size = old_size * 2;
  387. unsigned i;
  388. Closure *new_closures = client->allocator->alloc (client->allocator, sizeof (Closure) * new_size);
  389. memcpy (new_closures,
  390. client->info.connected.closures,
  391. sizeof (Closure) * old_size);
  392. /* build new free list */
  393. for (i = old_size; i < new_size - 1; i++)
  394. {
  395. new_closures[i].response_type = NULL;
  396. new_closures[i].closure = NULL;
  397. new_closures[i].closure_data = UINT_TO_POINTER (i+2);
  398. }
  399. new_closures[i].closure_data = UINT_TO_POINTER (client->info.connected.first_free_request_id);
  400. new_closures[i].response_type = NULL;
  401. new_closures[i].closure = NULL;
  402. client->info.connected.first_free_request_id = old_size + 1;
  403. client->allocator->free (client->allocator, client->info.connected.closures);
  404. client->info.connected.closures = new_closures;
  405. client->info.connected.closures_alloced = new_size;
  406. }
  407. static uint32_t
  408. uint32_to_le (uint32_t le)
  409. {
  410. #if IS_LITTLE_ENDIAN
  411. return le;
  412. #else
  413. return (le << 24) | (le >> 24)
  414. | ((le >> 8) & 0xff00)
  415. | ((le << 8) & 0xff0000);
  416. #endif
  417. }
  418. #define uint32_from_le uint32_to_le /* make the code more readable, i guess */
  419. static void
  420. enqueue_request (ProtobufC_RPC_Client *client,
  421. unsigned method_index,
  422. const ProtobufCMessage *input,
  423. ProtobufCClosure closure,
  424. void *closure_data)
  425. {
  426. uint32_t request_id;
  427. struct {
  428. uint32_t method_index;
  429. uint32_t packed_size;
  430. uint32_t request_id;
  431. } header;
  432. size_t packed_size;
  433. uint8_t *packed_data;
  434. Closure *cl;
  435. const ProtobufCServiceDescriptor *desc = client->base_service.descriptor;
  436. const ProtobufCMethodDescriptor *method = desc->methods + method_index;
  437. protobuf_c_assert (method_index < desc->n_methods);
  438. /* Allocate request_id */
  439. //protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_CONNECTED);
  440. if (client->info.connected.first_free_request_id == 0)
  441. grow_closure_array (client);
  442. request_id = client->info.connected.first_free_request_id;
  443. cl = client->info.connected.closures + (request_id - 1);
  444. client->info.connected.first_free_request_id = POINTER_TO_UINT (cl->closure_data);
  445. /* Pack message */
  446. packed_size = protobuf_c_message_get_packed_size (input);
  447. if (packed_size < client->allocator->max_alloca)
  448. packed_data = alloca (packed_size);
  449. else
  450. packed_data = client->allocator->alloc (client->allocator, packed_size);
  451. protobuf_c_message_pack (input, packed_data);
  452. /* Append to buffer */
  453. protobuf_c_assert (sizeof (header) == 12);
  454. header.method_index = uint32_to_le (method_index);
  455. header.packed_size = uint32_to_le (packed_size);
  456. header.request_id = request_id;
  457. protobuf_c_data_buffer_append (&client->outgoing, &header, 12);
  458. protobuf_c_data_buffer_append (&client->outgoing, packed_data, packed_size);
  459. /* Clean up if not using alloca() */
  460. if (packed_size >= client->allocator->max_alloca)
  461. client->allocator->free (client->allocator, packed_data);
  462. /* Add closure to request-tree */
  463. cl->response_type = method->output;
  464. cl->closure = closure;
  465. cl->closure_data = closure_data;
  466. }
  467. static void
  468. handle_client_fd_events (int fd,
  469. unsigned events,
  470. void *func_data)
  471. {
  472. ProtobufC_RPC_Client *client = func_data;
  473. protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_CONNECTED);
  474. if (events & PROTOBUF_C_EVENT_WRITABLE)
  475. {
  476. int write_rv = protobuf_c_data_buffer_writev (&client->outgoing,
  477. client->fd);
  478. if (write_rv < 0 && !errno_is_ignorable (errno))
  479. {
  480. client_failed (client,
  481. "writing to file-descriptor: %s",
  482. strerror (errno));
  483. return;
  484. }
  485. if (client->outgoing.size == 0)
  486. protobuf_c_dispatch_watch_fd (client->dispatch, client->fd,
  487. PROTOBUF_C_EVENT_READABLE,
  488. handle_client_fd_events, client);
  489. }
  490. if (events & PROTOBUF_C_EVENT_READABLE)
  491. {
  492. /* do read */
  493. int read_rv = protobuf_c_data_buffer_read_in_fd (&client->incoming,
  494. client->fd);
  495. if (read_rv < 0)
  496. {
  497. if (!errno_is_ignorable (errno))
  498. {
  499. client_failed (client,
  500. "reading from file-descriptor: %s",
  501. strerror (errno));
  502. }
  503. }
  504. else if (read_rv == 0)
  505. {
  506. /* handle eof */
  507. client_failed (client,
  508. "got end-of-file from server [%u bytes incoming, %u bytes outgoing]",
  509. client->incoming.size, client->outgoing.size);
  510. }
  511. else
  512. {
  513. /* try processing buffer */
  514. while (client->incoming.size >= 16)
  515. {
  516. uint32_t header[4];
  517. unsigned status_code, method_index, message_length, request_id;
  518. Closure *closure;
  519. uint8_t *packed_data;
  520. ProtobufCMessage *msg;
  521. protobuf_c_data_buffer_peek (&client->incoming, header, sizeof (header));
  522. status_code = uint32_from_le (header[0]);
  523. method_index = uint32_from_le (header[1]);
  524. message_length = uint32_from_le (header[2]);
  525. request_id = header[3]; /* already native-endian */
  526. if (16 + message_length > client->incoming.size)
  527. break;
  528. /* lookup request by id */
  529. if (request_id > client->info.connected.closures_alloced
  530. || request_id == 0
  531. || client->info.connected.closures[request_id-1].response_type == NULL)
  532. {
  533. client_failed (client, "bad request-id in response from server");
  534. return;
  535. }
  536. closure = client->info.connected.closures + (request_id - 1);
  537. /* read message and unpack */
  538. protobuf_c_data_buffer_discard (&client->incoming, 16);
  539. packed_data = client->allocator->alloc (client->allocator, message_length);
  540. protobuf_c_data_buffer_read (&client->incoming, packed_data, message_length);
  541. /* TODO: use fast temporary allocator */
  542. msg = protobuf_c_message_unpack (closure->response_type,
  543. client->allocator,
  544. message_length,
  545. packed_data);
  546. if (msg == NULL)
  547. {
  548. fprintf(stderr, "unable to unpack msg of length %u", message_length);
  549. client_failed (client, "failed to unpack message");
  550. client->allocator->free (client->allocator, packed_data);
  551. return;
  552. }
  553. /* invoke closure */
  554. closure->closure (msg, closure->closure_data);
  555. closure->response_type = NULL;
  556. closure->closure = NULL;
  557. closure->closure_data = UINT_TO_POINTER (client->info.connected.first_free_request_id);
  558. client->info.connected.first_free_request_id = request_id;
  559. /* clean up */
  560. protobuf_c_message_free_unpacked (msg, client->allocator);
  561. client->allocator->free (client->allocator, packed_data);
  562. }
  563. }
  564. }
  565. }
  566. static void
  567. update_connected_client_watch (ProtobufC_RPC_Client *client)
  568. {
  569. unsigned events = PROTOBUF_C_EVENT_READABLE;
  570. protobuf_c_assert (client->state == PROTOBUF_C_CLIENT_STATE_CONNECTED);
  571. protobuf_c_assert (client->fd >= 0);
  572. if (client->outgoing.size > 0)
  573. events |= PROTOBUF_C_EVENT_WRITABLE;
  574. protobuf_c_dispatch_watch_fd (client->dispatch,
  575. client->fd,
  576. events,
  577. handle_client_fd_events, client);
  578. }
  579. static void
  580. invoke_client_rpc (ProtobufCService *service,
  581. unsigned method_index,
  582. const ProtobufCMessage *input,
  583. ProtobufCClosure closure,
  584. void *closure_data)
  585. {
  586. ProtobufC_RPC_Client *client = (ProtobufC_RPC_Client *) service;
  587. protobuf_c_assert (service->invoke == invoke_client_rpc);
  588. switch (client->state)
  589. {
  590. case PROTOBUF_C_CLIENT_STATE_INIT:
  591. case PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP:
  592. case PROTOBUF_C_CLIENT_STATE_CONNECTING:
  593. enqueue_request (client, method_index, input, closure, closure_data);
  594. break;
  595. case PROTOBUF_C_CLIENT_STATE_CONNECTED:
  596. {
  597. int had_outgoing = (client->outgoing.size > 0);
  598. enqueue_request (client, method_index, input, closure, closure_data);
  599. if (!had_outgoing)
  600. update_connected_client_watch (client);
  601. }
  602. break;
  603. case PROTOBUF_C_CLIENT_STATE_FAILED_WAITING:
  604. case PROTOBUF_C_CLIENT_STATE_FAILED:
  605. case PROTOBUF_C_CLIENT_STATE_DESTROYED:
  606. closure (NULL, closure_data);
  607. break;
  608. }
  609. }
  610. static void
  611. destroy_client_rpc (ProtobufCService *service)
  612. {
  613. ProtobufC_RPC_Client *client = (ProtobufC_RPC_Client *) service;
  614. ProtobufC_RPC_ClientState state = client->state;
  615. unsigned i;
  616. unsigned n_closures = 0;
  617. Closure *closures = NULL;
  618. switch (state)
  619. {
  620. case PROTOBUF_C_CLIENT_STATE_INIT:
  621. protobuf_c_dispatch_remove_idle (client->info.init.idle);
  622. break;
  623. case PROTOBUF_C_CLIENT_STATE_NAME_LOOKUP:
  624. if (client->info.name_lookup.pending)
  625. {
  626. client->info.name_lookup.destroyed_while_pending = 1;
  627. return;
  628. }
  629. break;
  630. case PROTOBUF_C_CLIENT_STATE_CONNECTING:
  631. break;
  632. case PROTOBUF_C_CLIENT_STATE_CONNECTED:
  633. n_closures = client->info.connected.closures_alloced;
  634. closures = client->info.connected.closures;
  635. break;
  636. case PROTOBUF_C_CLIENT_STATE_FAILED_WAITING:
  637. protobuf_c_dispatch_remove_timer (client->info.failed_waiting.timer);
  638. client->allocator->free (client->allocator, client->info.failed_waiting.error_message);
  639. break;
  640. case PROTOBUF_C_CLIENT_STATE_FAILED:
  641. client->allocator->free (client->allocator, client->info.failed.error_message);
  642. break;
  643. case PROTOBUF_C_CLIENT_STATE_DESTROYED:
  644. protobuf_c_assert (0);
  645. break;
  646. }
  647. if (client->fd >= 0)
  648. {
  649. protobuf_c_dispatch_close_fd (client->dispatch, client->fd);
  650. client->fd = -1;
  651. }
  652. protobuf_c_data_buffer_clear (&client->incoming);
  653. protobuf_c_data_buffer_clear (&client->outgoing);
  654. client->state = PROTOBUF_C_CLIENT_STATE_DESTROYED;
  655. client->allocator->free (client->allocator, client->name);
  656. /* free closures only once we are in the destroyed state */
  657. for (i = 0; i < n_closures; i++)
  658. if (closures[i].response_type != NULL)
  659. closures[i].closure (NULL, closures[i].closure_data);
  660. if (closures)
  661. client->allocator->free (client->allocator, closures);
  662. client->allocator->free (client->allocator, client);
  663. }
  664. static void
  665. trivial_sync_libc_resolver (ProtobufCDispatch *dispatch,
  666. const char *name,
  667. ProtobufC_NameLookup_Found found_func,
  668. ProtobufC_NameLookup_Failed failed_func,
  669. void *callback_data)
  670. {
  671. struct hostent *ent;
  672. ent = gethostbyname (name);
  673. if (ent == NULL)
  674. failed_func (hstrerror (h_errno), callback_data);
  675. else
  676. found_func ((const uint8_t *) ent->h_addr_list[0], callback_data);
  677. }
  678. ProtobufCService *protobuf_c_rpc_client_new (ProtobufC_RPC_AddressType type,
  679. const char *name,
  680. const ProtobufCServiceDescriptor *descriptor,
  681. ProtobufCDispatch *orig_dispatch)
  682. {
  683. ProtobufCDispatch *dispatch = orig_dispatch ? orig_dispatch : protobuf_c_dispatch_default ();
  684. ProtobufCAllocator *allocator = protobuf_c_dispatch_peek_allocator (dispatch);
  685. ProtobufC_RPC_Client *rv = allocator->alloc (allocator, sizeof (ProtobufC_RPC_Client));
  686. rv->base_service.descriptor = descriptor;
  687. rv->base_service.invoke = invoke_client_rpc;
  688. rv->base_service.destroy = destroy_client_rpc;
  689. protobuf_c_data_buffer_init (&rv->incoming, allocator);
  690. protobuf_c_data_buffer_init (&rv->outgoing, allocator);
  691. rv->allocator = allocator;
  692. rv->dispatch = dispatch;
  693. rv->address_type = type;
  694. rv->name = strcpy (allocator->alloc (allocator, strlen (name) + 1), name);
  695. rv->state = PROTOBUF_C_CLIENT_STATE_INIT;
  696. rv->fd = -1;
  697. rv->autoreconnect = 1;
  698. rv->autoreconnect_millis = 2*1000;
  699. rv->resolver = trivial_sync_libc_resolver;
  700. rv->error_handler = error_handler;
  701. rv->error_handler_data = "protobuf-c rpc client";
  702. rv->info.init.idle = protobuf_c_dispatch_add_idle (dispatch, handle_init_idle, rv);
  703. return &rv->base_service;
  704. }
  705. protobuf_c_boolean
  706. protobuf_c_rpc_client_is_connected (ProtobufC_RPC_Client *client)
  707. {
  708. return client->state == PROTOBUF_C_CLIENT_STATE_CONNECTED;
  709. }
  710. void
  711. protobuf_c_rpc_client_set_autoreconnect_period (ProtobufC_RPC_Client *client,
  712. unsigned millis)
  713. {
  714. client->autoreconnect = 1;
  715. client->autoreconnect_millis = millis;
  716. }
  717. void
  718. protobuf_c_rpc_client_set_error_handler (ProtobufC_RPC_Client *client,
  719. ProtobufC_RPC_Error_Func func,
  720. void *func_data)
  721. {
  722. client->error_handler = func;
  723. client->error_handler_data = func_data;
  724. }
  725. void
  726. protobuf_c_rpc_client_disable_autoreconnect (ProtobufC_RPC_Client *client)
  727. {
  728. client->autoreconnect = 0;
  729. }
  730. /* === Server === */
  731. typedef struct _ServerRequest ServerRequest;
  732. typedef struct _ServerConnection ServerConnection;
  733. struct _ServerRequest
  734. {
  735. uint32_t request_id; /* in little-endian */
  736. uint32_t method_index; /* in native-endian */
  737. ServerConnection *conn;
  738. ProtobufC_RPC_Server *server;
  739. union {
  740. /* if conn != NULL, then the request is alive: */
  741. struct { ServerRequest *prev, *next; } alive;
  742. /* if conn == NULL, then the request is defunct: */
  743. struct { ProtobufCAllocator *allocator; } defunct;
  744. /* well, if it is in the recycled list, then it's recycled :/ */
  745. struct { ServerRequest *next; } recycled;
  746. } info;
  747. };
  748. struct _ServerConnection
  749. {
  750. int fd;
  751. ProtobufCDataBuffer incoming, outgoing;
  752. ProtobufC_RPC_Server *server;
  753. ServerConnection *prev, *next;
  754. unsigned n_pending_requests;
  755. ServerRequest *first_pending_request, *last_pending_request;
  756. };
  757. /* When we get a response in the wrong thread,
  758. we proxy it over a system pipe. Actually, we allocate one
  759. of these structures and pass the pointer over the pipe. */
  760. typedef struct _ProxyResponse ProxyResponse;
  761. struct _ProxyResponse
  762. {
  763. ServerRequest *request;
  764. unsigned len;
  765. /* data follows the structure */
  766. };
  767. struct _ProtobufC_RPC_Server
  768. {
  769. ProtobufCDispatch *dispatch;
  770. ProtobufCAllocator *allocator;
  771. ProtobufCService *underlying;
  772. ProtobufC_RPC_AddressType address_type;
  773. char *bind_name;
  774. ServerConnection *first_connection, *last_connection;
  775. ProtobufC_FD listening_fd;
  776. ServerRequest *recycled_requests;
  777. /* multithreading support */
  778. ProtobufC_RPC_IsRpcThreadFunc is_rpc_thread_func;
  779. void * is_rpc_thread_data;
  780. int proxy_pipe[2];
  781. unsigned proxy_extra_data_len;
  782. uint8_t proxy_extra_data[sizeof (void*)];
  783. ProtobufC_RPC_Error_Func error_handler;
  784. void *error_handler_data;
  785. /* configuration */
  786. unsigned max_pending_requests_per_connection;
  787. };
  788. #define GET_PENDING_REQUEST_LIST(conn) \
  789. ServerRequest *, conn->first_pending_request, conn->last_pending_request, info.alive.prev, info.alive.next
  790. #define GET_CONNECTION_LIST(server) \
  791. ServerConnection *, server->first_connection, server->last_connection, prev, next
  792. static void
  793. server_connection_close (ServerConnection *conn)
  794. {
  795. ProtobufCAllocator *allocator = conn->server->allocator;
  796. /* general cleanup */
  797. protobuf_c_dispatch_close_fd (conn->server->dispatch, conn->fd);
  798. conn->fd = -1;
  799. protobuf_c_data_buffer_clear (&conn->incoming);
  800. protobuf_c_data_buffer_clear (&conn->outgoing);
  801. /* remove this connection from the server's list */
  802. GSK_LIST_REMOVE (GET_CONNECTION_LIST (conn->server), conn);
  803. /* disassocate all the requests from the connection */
  804. while (conn->first_pending_request != NULL)
  805. {
  806. ServerRequest *req = conn->first_pending_request;
  807. conn->first_pending_request = req->info.alive.next;
  808. req->conn = NULL;
  809. req->info.defunct.allocator = allocator;
  810. }
  811. /* free the connection itself */
  812. allocator->free (allocator, conn);
  813. }
  814. static void
  815. server_failed_literal (ProtobufC_RPC_Server *server,
  816. ProtobufC_RPC_Error_Code code,
  817. const char *msg)
  818. {
  819. if (server->error_handler != NULL)
  820. server->error_handler (code, msg, server->error_handler_data);
  821. }
  822. #if 0
  823. static void
  824. server_failed (ProtobufC_RPC_Server *server,
  825. ProtobufC_RPC_Error_Code code,
  826. const char *format,
  827. ...)
  828. {
  829. va_list args;
  830. char buf[MAX_FAILED_MSG_LENGTH];
  831. va_start (args, format);
  832. vsnprintf (buf, sizeof (buf), format, args);
  833. buf[sizeof(buf)-1] = 0;
  834. va_end (args);
  835. server_failed_literal (server, code, buf);
  836. }
  837. #endif
  838. static protobuf_c_boolean
  839. address_to_name (const struct sockaddr *addr,
  840. unsigned addr_len,
  841. char *name_out,
  842. unsigned name_out_buf_length)
  843. {
  844. if (addr->sa_family == PF_INET)
  845. {
  846. /* convert to dotted address + port */
  847. const struct sockaddr_in *addr_in = (const struct sockaddr_in *) addr;
  848. const uint8_t *addr = (const uint8_t *) &(addr_in->sin_addr);
  849. uint16_t port = htons (addr_in->sin_port);
  850. snprintf (name_out, name_out_buf_length,
  851. "%u.%u.%u.%u:%u",
  852. addr[0], addr[1], addr[2], addr[3], port);
  853. return TRUE;
  854. }
  855. return FALSE;
  856. }
  857. static void
  858. server_connection_failed (ServerConnection *conn,
  859. ProtobufC_RPC_Error_Code code,
  860. const char *format,
  861. ...)
  862. {
  863. char remote_addr_name[64];
  864. char msg[MAX_FAILED_MSG_LENGTH];
  865. char *msg_end = msg + sizeof (msg);
  866. char *msg_at;
  867. struct sockaddr addr;
  868. socklen_t addr_len = sizeof (addr);
  869. va_list args;
  870. /* if we can, find the remote name of this connection */
  871. if (getpeername (conn->fd, &addr, &addr_len) == 0
  872. && address_to_name (&addr, addr_len, remote_addr_name, sizeof (remote_addr_name)))
  873. snprintf (msg, sizeof (msg), "connection to %s from %s: ",
  874. conn->server->bind_name, remote_addr_name);
  875. else
  876. snprintf (msg, sizeof (msg), "connection to %s: ",
  877. conn->server->bind_name);
  878. msg[sizeof(msg)-1] = 0;
  879. msg_at = strchr (msg, 0);
  880. /* do vsnprintf() */
  881. va_start (args, format);
  882. vsnprintf(msg_at, msg_end - msg_at, format, args);
  883. va_end (args);
  884. msg[sizeof(msg)-1] = 0;
  885. /* invoke server error hook */
  886. server_failed_literal (conn->server, code, msg);
  887. server_connection_close (conn);
  888. }
  889. static ServerRequest *
  890. create_server_request (ServerConnection *conn,
  891. uint32_t request_id,
  892. uint32_t method_index)
  893. {
  894. ServerRequest *rv;
  895. if (conn->server->recycled_requests != NULL)
  896. {
  897. rv = conn->server->recycled_requests;
  898. conn->server->recycled_requests = rv->info.recycled.next;
  899. }
  900. else
  901. {
  902. ProtobufCAllocator *allocator = conn->server->allocator;
  903. rv = allocator->alloc (allocator, sizeof (ServerRequest));
  904. }
  905. rv->server = conn->server;
  906. rv->conn = conn;
  907. rv->request_id = request_id;
  908. rv->method_index = method_index;
  909. conn->n_pending_requests++;
  910. GSK_LIST_APPEND (GET_PENDING_REQUEST_LIST (conn), rv);
  911. return rv;
  912. }
  913. static void
  914. free_server_request (ProtobufC_RPC_Server *server,
  915. ServerRequest *request)
  916. {
  917. #if RECYCLE_REQUESTS
  918. /* recycle request */
  919. request->info.recycled.next = server->recycled_requests;
  920. server->recycled_requests = request;
  921. #else
  922. /* free the request immediately */
  923. server->allocator->free (server->allocator, request);
  924. #endif
  925. }
  926. static void handle_server_connection_events (int fd,
  927. unsigned events,
  928. void *data);
  929. static void
  930. server_connection_response_closure (const ProtobufCMessage *message,
  931. void *closure_data)
  932. {
  933. ServerRequest *request = closure_data;
  934. ProtobufC_RPC_Server *server = request->server;
  935. protobuf_c_boolean must_proxy = 0;
  936. ProtobufCAllocator *allocator = server->allocator;
  937. if (server->is_rpc_thread_func != NULL)
  938. {
  939. must_proxy = !server->is_rpc_thread_func (server,
  940. server->dispatch,
  941. server->is_rpc_thread_data);
  942. }
  943. uint8_t buffer_slab[512];
  944. ProtobufCBufferSimple buffer_simple = PROTOBUF_C_BUFFER_SIMPLE_INIT (buffer_slab);
  945. if (message == NULL)
  946. {
  947. /* send failed status */
  948. uint32_t header[4];
  949. header[0] = uint32_to_le (PROTOBUF_C_STATUS_CODE_SERVICE_FAILED);
  950. header[1] = uint32_to_le (request->method_index);
  951. header[2] = 0; /* no message */
  952. header[3] = request->request_id;
  953. protobuf_c_buffer_simple_append (&buffer_simple.base,
  954. 16, (uint8_t *) header);
  955. }
  956. else
  957. {
  958. /* send success response */
  959. uint32_t header[4];
  960. header[0] = uint32_to_le (PROTOBUF_C_STATUS_CODE_SUCCESS);
  961. header[1] = uint32_to_le (request->method_index);
  962. header[3] = request->request_id;
  963. protobuf_c_buffer_simple_append (&buffer_simple.base,
  964. 16, (uint8_t *) header);
  965. protobuf_c_message_pack_to_buffer (message, &buffer_simple.base);
  966. ((uint32_t *)buffer_simple.data)[2] = uint32_to_le (buffer_simple.len - 16);
  967. }
  968. if (must_proxy)
  969. {
  970. ProxyResponse *pr = allocator->alloc (allocator, sizeof (ProxyResponse) + buffer_simple.len);
  971. int rv;
  972. pr->request = request;
  973. pr->len = buffer_simple.len;
  974. memcpy (pr + 1, buffer_simple.data, buffer_simple.len);
  975. /* write pointer to proxy pipe */
  976. retry_write:
  977. rv = write (server->proxy_pipe[1], &pr, sizeof (void*));
  978. if (rv < 0)
  979. {
  980. if (errno == EINTR || errno == EAGAIN)
  981. goto retry_write;
  982. server_failed_literal (server, PROTOBUF_C_ERROR_CODE_PROXY_PROBLEM,
  983. "error writing to proxy-pipe");
  984. allocator->free (allocator, pr);
  985. }
  986. else if (rv < sizeof (void *))
  987. {
  988. server_failed_literal (server, PROTOBUF_C_ERROR_CODE_PROXY_PROBLEM,
  989. "partial write to proxy-pipe");
  990. allocator->free (allocator, pr);
  991. }
  992. }
  993. else if (request->conn == NULL)
  994. {
  995. /* defunct request */
  996. allocator->free (allocator, request);
  997. free_server_request (server, request);
  998. }
  999. else
  1000. {
  1001. ServerConnection *conn = request->conn;
  1002. protobuf_c_boolean must_set_output_watch = (conn->outgoing.size == 0);
  1003. protobuf_c_data_buffer_append (&conn->outgoing, buffer_simple.data, buffer_simple.len);
  1004. if (must_set_output_watch)
  1005. protobuf_c_dispatch_watch_fd (conn->server->dispatch,
  1006. conn->fd,
  1007. PROTOBUF_C_EVENT_READABLE|PROTOBUF_C_EVENT_WRITABLE,
  1008. handle_server_connection_events,
  1009. conn);
  1010. GSK_LIST_REMOVE (GET_PENDING_REQUEST_LIST (conn), request);
  1011. conn->n_pending_requests--;
  1012. free_server_request (server, request);
  1013. }
  1014. PROTOBUF_C_BUFFER_SIMPLE_CLEAR (&buffer_simple);
  1015. }
  1016. static void
  1017. handle_server_connection_events (int fd,
  1018. unsigned events,
  1019. void *data)
  1020. {
  1021. ServerConnection *conn = data;
  1022. ProtobufCService *service = conn->server->underlying;
  1023. ProtobufCAllocator *allocator = conn->server->allocator;
  1024. if (events & PROTOBUF_C_EVENT_READABLE)
  1025. {
  1026. int read_rv = protobuf_c_data_buffer_read_in_fd (&conn->incoming, fd);
  1027. if (read_rv < 0)
  1028. {
  1029. if (!errno_is_ignorable (errno))
  1030. {
  1031. server_connection_failed (conn,
  1032. PROTOBUF_C_ERROR_CODE_CLIENT_TERMINATED,
  1033. "reading from file-descriptor: %s",
  1034. strerror (errno));
  1035. return;
  1036. }
  1037. }
  1038. else if (read_rv == 0)
  1039. {
  1040. if (conn->first_pending_request != NULL)
  1041. server_connection_failed (conn,
  1042. PROTOBUF_C_ERROR_CODE_CLIENT_TERMINATED,
  1043. "closed while calls pending");
  1044. else
  1045. server_connection_close (conn);
  1046. return;
  1047. }
  1048. else
  1049. while (conn->incoming.size >= 12)
  1050. {
  1051. uint32_t header[3];
  1052. uint32_t method_index, message_length, request_id;
  1053. uint8_t *packed_data;
  1054. ProtobufCMessage *message;
  1055. ServerRequest *server_request;
  1056. protobuf_c_data_buffer_peek (&conn->incoming, header, 12);
  1057. method_index = uint32_from_le (header[0]);
  1058. message_length = uint32_from_le (header[1]);
  1059. request_id = header[2]; /* store in whatever endianness it comes in */
  1060. if (conn->incoming.size < 12 + message_length)
  1061. break;
  1062. if (method_index >= conn->server->underlying->descriptor->n_methods)
  1063. {
  1064. server_connection_failed (conn,
  1065. PROTOBUF_C_ERROR_CODE_BAD_REQUEST,
  1066. "bad method_index %u", method_index);
  1067. return;
  1068. }
  1069. /* Read message */
  1070. protobuf_c_data_buffer_discard (&conn->incoming, 12);
  1071. packed_data = allocator->alloc (allocator, message_length);
  1072. protobuf_c_data_buffer_read (&conn->incoming, packed_data, message_length);
  1073. /* Unpack message */
  1074. message = protobuf_c_message_unpack (service->descriptor->methods[method_index].input,
  1075. allocator, message_length, packed_data);
  1076. allocator->free (allocator, packed_data);
  1077. if (message == NULL)
  1078. {
  1079. server_connection_failed (conn,
  1080. PROTOBUF_C_ERROR_CODE_BAD_REQUEST,
  1081. "error unpacking message");
  1082. return;
  1083. }
  1084. /* Invoke service (note that it may call back immediately) */
  1085. server_request = create_server_request (conn, request_id, method_index);
  1086. service->invoke (service, method_index, message,
  1087. server_connection_response_closure, server_request);
  1088. protobuf_c_message_free_unpacked (message, allocator);
  1089. }
  1090. }
  1091. if ((events & PROTOBUF_C_EVENT_WRITABLE) != 0
  1092. && conn->outgoing.size > 0)
  1093. {
  1094. int write_rv = protobuf_c_data_buffer_writev (&conn->outgoing, fd);
  1095. if (write_rv < 0)
  1096. {
  1097. if (!errno_is_ignorable (errno))
  1098. {
  1099. server_connection_failed (conn,
  1100. PROTOBUF_C_ERROR_CODE_CLIENT_TERMINATED,
  1101. "writing to file-descriptor: %s",
  1102. strerror (errno));
  1103. return;
  1104. }
  1105. }
  1106. if (conn->outgoing.size == 0)
  1107. protobuf_c_dispatch_watch_fd (conn->server->dispatch, conn->fd, PROTOBUF_C_EVENT_READABLE,
  1108. handle_server_connection_events, conn);
  1109. }
  1110. }
  1111. static void
  1112. handle_server_listener_readable (int fd,
  1113. unsigned events,
  1114. void *data)
  1115. {
  1116. ProtobufC_RPC_Server *server = data;
  1117. struct sockaddr addr;
  1118. socklen_t addr_len = sizeof (addr);
  1119. int new_fd = accept (fd, &addr, &addr_len);
  1120. ServerConnection *conn;
  1121. ProtobufCAllocator *allocator = server->allocator;
  1122. if (new_fd < 0)
  1123. {
  1124. if (errno_is_ignorable (errno))
  1125. return;
  1126. fprintf (stderr, "error accept()ing file descriptor: %s\n",
  1127. strerror (errno));
  1128. return;
  1129. }
  1130. conn = allocator->alloc (allocator, sizeof (ServerConnection));
  1131. conn->fd = new_fd;
  1132. protobuf_c_data_buffer_init (&conn->incoming, server->allocator);
  1133. protobuf_c_data_buffer_init (&conn->outgoing, server->allocator);
  1134. conn->n_pending_requests = 0;
  1135. conn->first_pending_request = conn->last_pending_request = NULL;
  1136. conn->server = server;
  1137. GSK_LIST_APPEND (GET_CONNECTION_LIST (server), conn);
  1138. protobuf_c_dispatch_watch_fd (server->dispatch, conn->fd, PROTOBUF_C_EVENT_READABLE,
  1139. handle_server_connection_events, conn);
  1140. }
  1141. static ProtobufC_RPC_Server *
  1142. server_new_from_fd (ProtobufC_FD listening_fd,
  1143. ProtobufC_RPC_AddressType address_type,
  1144. const char *bind_name,
  1145. ProtobufCService *service,
  1146. ProtobufCDispatch *orig_dispatch)
  1147. {
  1148. ProtobufCDispatch *dispatch = orig_dispatch ? orig_dispatch : protobuf_c_dispatch_default ();
  1149. ProtobufCAllocator *allocator = protobuf_c_dispatch_peek_allocator (dispatch);
  1150. ProtobufC_RPC_Server *server = allocator->alloc (allocator, sizeof (ProtobufC_RPC_Server));
  1151. server->dispatch = dispatch;
  1152. server->allocator = allocator;
  1153. server->underlying = service;
  1154. server->first_connection = server->last_connection = NULL;
  1155. server->max_pending_requests_per_connection = 32;
  1156. server->address_type = address_type;
  1157. server->bind_name = allocator->alloc (allocator, strlen (bind_name) + 1);
  1158. server->error_handler = error_handler;
  1159. server->error_handler_data = "protobuf-c rpc server";
  1160. server->listening_fd = listening_fd;
  1161. server->recycled_requests = NULL;
  1162. server->is_rpc_thread_func = NULL;
  1163. server->is_rpc_thread_data = NULL;
  1164. server->proxy_pipe[0] = server->proxy_pipe[1] = -1;
  1165. server->proxy_extra_data_len = 0;
  1166. strcpy (server->bind_name, bind_name);
  1167. set_fd_nonblocking (listening_fd);
  1168. protobuf_c_dispatch_watch_fd (dispatch, listening_fd, PROTOBUF_C_EVENT_READABLE,
  1169. handle_server_listener_readable, server);
  1170. return server;
  1171. }
  1172. /* this function is for handling the common problem
  1173. that we bind over-and-over again to the same
  1174. unix path.
  1175. ideally, you'd think the OS's SO_REUSEADDR flag would
  1176. cause this to happen, but it doesn't,
  1177. at least on my linux 2.6 box.
  1178. in fact, we really need a way to test without
  1179. actually connecting to the remote server,
  1180. which might annoy it.
  1181. XXX: we should survey what others do here... like x-windows...
  1182. */
  1183. /* NOTE: stolen from gsk, obviously */
  1184. static void
  1185. _gsk_socket_address_local_maybe_delete_stale_socket (const char *path,
  1186. struct sockaddr *addr,
  1187. unsigned addr_len)
  1188. {
  1189. int fd;
  1190. struct stat statbuf;
  1191. if (stat (path, &statbuf) < 0)
  1192. return;
  1193. if (!S_ISSOCK (statbuf.st_mode))
  1194. {
  1195. fprintf (stderr, "%s existed but was not a socket\n", path);
  1196. return;
  1197. }
  1198. fd = socket (PF_UNIX, SOCK_STREAM, 0);
  1199. if (fd < 0)
  1200. return;
  1201. set_fd_nonblocking (fd);
  1202. if (connect (fd, addr, addr_len) < 0)
  1203. {
  1204. if (errno == EINPROGRESS)
  1205. {
  1206. close (fd);
  1207. return;
  1208. }
  1209. }
  1210. else
  1211. {
  1212. close (fd);
  1213. return;
  1214. }
  1215. /* ok, we should delete the stale socket */
  1216. close (fd);
  1217. if (unlink (path) < 0)
  1218. fprintf (stderr, "unable to delete %s: %s\n",
  1219. path, strerror(errno));
  1220. }
  1221. ProtobufC_RPC_Server *
  1222. protobuf_c_rpc_server_new (ProtobufC_RPC_AddressType type,
  1223. const char *name,
  1224. ProtobufCService *service,
  1225. ProtobufCDispatch *dispatch)
  1226. {
  1227. int fd = -1;
  1228. int protocol_family;
  1229. struct sockaddr *address;
  1230. socklen_t address_len;
  1231. struct sockaddr_un addr_un;
  1232. struct sockaddr_in addr_in;
  1233. switch (type)
  1234. {
  1235. case PROTOBUF_C_RPC_ADDRESS_LOCAL:
  1236. protocol_family = PF_UNIX;
  1237. memset (&addr_un, 0, sizeof (addr_un));
  1238. addr_un.sun_family = AF_LOCAL;
  1239. strncpy (addr_un.sun_path, name, sizeof (addr_un.sun_path));
  1240. address_len = sizeof (addr_un);
  1241. address = (struct sockaddr *) (&addr_un);
  1242. _gsk_socket_address_local_maybe_delete_stale_socket (name,
  1243. address,
  1244. address_len);
  1245. break;
  1246. case PROTOBUF_C_RPC_ADDRESS_TCP:
  1247. protocol_family = PF_INET;
  1248. memset (&addr_in, 0, sizeof (addr_in));
  1249. addr_in.sin_family = AF_INET;
  1250. {
  1251. unsigned port = atoi (name);
  1252. addr_in.sin_port = htons (port);
  1253. }
  1254. address_len = sizeof (addr_in);
  1255. address = (struct sockaddr *) (&addr_in);
  1256. break;
  1257. default:
  1258. protobuf_c_assert (0);
  1259. }
  1260. fd = socket (protocol_family, SOCK_STREAM, 0);
  1261. if (fd < 0)
  1262. {
  1263. fprintf (stderr, "protobuf_c_rpc_server_new: socket() failed: %s\n",
  1264. strerror (errno));
  1265. return NULL;
  1266. }
  1267. if (bind (fd, address, address_len) < 0)
  1268. {
  1269. fprintf (stderr, "protobuf_c_rpc_server_new: error binding to port: %s\n",
  1270. strerror (errno));
  1271. return NULL;
  1272. }
  1273. if (listen (fd, 255) < 0)
  1274. {
  1275. fprintf (stderr, "protobuf_c_rpc_server_new: listen() failed: %s\n",
  1276. strerror (errno));
  1277. return NULL;
  1278. }
  1279. return server_new_from_fd (fd, type, name, service, dispatch);
  1280. }
  1281. ProtobufCService *
  1282. protobuf_c_rpc_server_destroy (ProtobufC_RPC_Server *server,
  1283. protobuf_c_boolean destroy_underlying)
  1284. {
  1285. ProtobufCService *rv = destroy_underlying ? NULL : server->underlying;
  1286. while (server->first_connection != NULL)
  1287. server_connection_close (server->first_connection);
  1288. if (server->address_type == PROTOBUF_C_RPC_ADDRESS_LOCAL)
  1289. unlink (server->bind_name);
  1290. server->allocator->free (server->allocator, server->bind_name);
  1291. while (server->recycled_requests != NULL)
  1292. {
  1293. ServerRequest *req = server->recycled_requests;
  1294. server->recycled_requests = req->info.recycled.next;
  1295. server->allocator->free (server->allocator, req);
  1296. }
  1297. protobuf_c_dispatch_close_fd (server->dispatch, server->listening_fd);
  1298. if (destroy_underlying)
  1299. protobuf_c_service_destroy (server->underlying);
  1300. server->allocator->free (server->allocator, server);
  1301. return rv;
  1302. }
  1303. /* Number of proxied requests to try to grab in a single read */
  1304. #define PROXY_BUF_SIZE 256
  1305. static void
  1306. handle_proxy_pipe_readable (ProtobufC_FD fd,
  1307. unsigned events,
  1308. void *callback_data)
  1309. {
  1310. int nread;
  1311. ProtobufC_RPC_Server *server = callback_data;
  1312. ProtobufCAllocator *allocator = server->allocator;
  1313. union {
  1314. char buf[sizeof(void*) * PROXY_BUF_SIZE];
  1315. ProxyResponse *responses[PROXY_BUF_SIZE];
  1316. } u;
  1317. unsigned amt, i;
  1318. memcpy (u.buf, server->proxy_extra_data, server->proxy_extra_data_len);
  1319. nread = read (fd, u.buf + server->proxy_extra_data_len, sizeof (u.buf) - server->proxy_extra_data_len);
  1320. if (nread <= 0)
  1321. return; /* TODO: handle 0 and non-retryable errors separately */
  1322. amt = server->proxy_extra_data_len + nread;
  1323. for (i = 0; i < amt / sizeof(void*); i++)
  1324. {
  1325. ProxyResponse *pr = u.responses[i];
  1326. ServerRequest *request = pr->request;
  1327. if (request->conn == NULL)
  1328. {
  1329. /* defunct request */
  1330. allocator->free (allocator, request);
  1331. }
  1332. else
  1333. {
  1334. ServerConnection *conn = request->conn;
  1335. protobuf_c_boolean must_set_output_watch = (conn->outgoing.size == 0);
  1336. protobuf_c_data_buffer_append (&conn->outgoing, (uint8_t*)(pr+1), pr->len);
  1337. if (must_set_output_watch)
  1338. protobuf_c_dispatch_watch_fd (conn->server->dispatch,
  1339. conn->fd,
  1340. PROTOBUF_C_EVENT_READABLE|PROTOBUF_C_EVENT_WRITABLE,
  1341. handle_server_connection_events,
  1342. conn);
  1343. GSK_LIST_REMOVE (GET_PENDING_REQUEST_LIST (conn), request);
  1344. conn->n_pending_requests--;
  1345. f

Large files files are truncated, but you can click here to view the full file