plugin_transport_unix.c 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2010-2014 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file transport/plugin_transport_unix.c
  18. * @brief Transport plugin using unix domain sockets (!)
  19. * Clearly, can only be used locally on Unix/Linux hosts...
  20. * ONLY INTENDED FOR TESTING!!!
  21. * @author Christian Grothoff
  22. * @author Nathan Evans
  23. */
  24. #include "platform.h"
  25. #include "gnunet_util_lib.h"
  26. #include "gnunet_hello_lib.h"
  27. #include "gnunet_protocols.h"
  28. #include "gnunet_statistics_service.h"
  29. #include "gnunet_transport_service.h"
  30. #include "gnunet_transport_plugin.h"
  31. #include "transport.h"
  32. /**
  33. * Return code we give on 'send' if we failed to send right now
  34. * but it makes sense to retry later. (Note: we might want to
  35. * move this to the plugin API!?).
  36. */
  37. #define RETRY 0
  38. /**
  39. * Name of the plugin.
  40. */
  41. #define PLUGIN_NAME "unix"
  42. /**
  43. * Options for UNIX Domain addresses.
  44. */
  45. enum UNIX_ADDRESS_OPTIONS
  46. {
  47. /**
  48. * No special options.
  49. */
  50. UNIX_OPTIONS_NONE = 0,
  51. /**
  52. * Linux abstract domain sockets should be used.
  53. */
  54. UNIX_OPTIONS_USE_ABSTRACT_SOCKETS = 1
  55. };
  56. /**
  57. * How long until we give up on transmitting the welcome message?
  58. */
  59. #define HOSTNAME_RESOLVE_TIMEOUT \
  60. GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
  61. #define LOG(kind, ...) GNUNET_log_from (kind, "transport-unix", __VA_ARGS__)
  62. GNUNET_NETWORK_STRUCT_BEGIN
  63. /**
  64. * Binary format for an UNIX Domain Socket address in GNUnet.
  65. */
  66. struct UnixAddress
  67. {
  68. /**
  69. * Options to use for the address, in NBO
  70. */
  71. uint32_t options GNUNET_PACKED;
  72. /**
  73. * Length of the address (path length), in NBO
  74. */
  75. uint32_t addrlen GNUNET_PACKED;
  76. /* followed by actual path */
  77. };
  78. /**
  79. * UNIX Message-Packet header.
  80. */
  81. struct UNIXMessage
  82. {
  83. /**
  84. * Message header.
  85. */
  86. struct GNUNET_MessageHeader header;
  87. /**
  88. * What is the identity of the sender (GNUNET_hash of public key)
  89. */
  90. struct GNUNET_PeerIdentity sender;
  91. };
  92. GNUNET_NETWORK_STRUCT_END
  93. /**
  94. * Information we track for a message awaiting transmission.
  95. */
  96. struct UNIXMessageWrapper
  97. {
  98. /**
  99. * We keep messages in a doubly linked list.
  100. */
  101. struct UNIXMessageWrapper *next;
  102. /**
  103. * We keep messages in a doubly linked list.
  104. */
  105. struct UNIXMessageWrapper *prev;
  106. /**
  107. * The actual payload (allocated separately right now).
  108. */
  109. struct UNIXMessage *msg;
  110. /**
  111. * Session this message belongs to.
  112. */
  113. struct GNUNET_ATS_Session *session;
  114. /**
  115. * Function to call upon transmission.
  116. */
  117. GNUNET_TRANSPORT_TransmitContinuation cont;
  118. /**
  119. * Closure for @e cont.
  120. */
  121. void *cont_cls;
  122. /**
  123. * Timeout for this message.
  124. */
  125. struct GNUNET_TIME_Absolute timeout;
  126. /**
  127. * Number of bytes in @e msg.
  128. */
  129. size_t msgsize;
  130. /**
  131. * Number of bytes of payload encapsulated in @e msg.
  132. */
  133. size_t payload;
  134. /**
  135. * Priority of the message (ignored, just dragged along in UNIX).
  136. */
  137. unsigned int priority;
  138. };
  139. /**
  140. * Handle for a session.
  141. */
  142. struct GNUNET_ATS_Session
  143. {
  144. /**
  145. * Sessions with pending messages (!) are kept in a DLL.
  146. */
  147. struct GNUNET_ATS_Session *next;
  148. /**
  149. * Sessions with pending messages (!) are kept in a DLL.
  150. */
  151. struct GNUNET_ATS_Session *prev;
  152. /**
  153. * To whom are we talking to (set to our identity
  154. * if we are still waiting for the welcome message).
  155. *
  156. * FIXME: information duplicated with 'peer' in address!
  157. */
  158. struct GNUNET_PeerIdentity target;
  159. /**
  160. * Pointer to the global plugin struct.
  161. */
  162. struct Plugin *plugin;
  163. /**
  164. * Address of the other peer.
  165. */
  166. struct GNUNET_HELLO_Address *address;
  167. /**
  168. * Number of bytes we currently have in our write queue.
  169. */
  170. unsigned long long bytes_in_queue;
  171. /**
  172. * Timeout for this session.
  173. */
  174. struct GNUNET_TIME_Absolute timeout;
  175. /**
  176. * Session timeout task.
  177. */
  178. struct GNUNET_SCHEDULER_Task *timeout_task;
  179. /**
  180. * Number of messages we currently have in our write queue.
  181. */
  182. unsigned int msgs_in_queue;
  183. };
  184. /**
  185. * Encapsulation of all of the state of the plugin.
  186. */
  187. struct Plugin;
  188. /**
  189. * Information we keep for each of our listen sockets.
  190. */
  191. struct UNIX_Sock_Info
  192. {
  193. /**
  194. * The network handle
  195. */
  196. struct GNUNET_NETWORK_Handle *desc;
  197. };
  198. /**
  199. * Encapsulation of all of the state of the plugin.
  200. */
  201. struct Plugin
  202. {
  203. /**
  204. * ID of task used to update our addresses when one expires.
  205. */
  206. struct GNUNET_SCHEDULER_Task *address_update_task;
  207. /**
  208. * ID of read task
  209. */
  210. struct GNUNET_SCHEDULER_Task *read_task;
  211. /**
  212. * ID of write task
  213. */
  214. struct GNUNET_SCHEDULER_Task *write_task;
  215. /**
  216. * Number of bytes we currently have in our write queues.
  217. */
  218. unsigned long long bytes_in_queue;
  219. /**
  220. * Our environment.
  221. */
  222. struct GNUNET_TRANSPORT_PluginEnvironment *env;
  223. /**
  224. * Sessions (map from peer identity to `struct GNUNET_ATS_Session`)
  225. */
  226. struct GNUNET_CONTAINER_MultiPeerMap *session_map;
  227. /**
  228. * Head of queue of messages to transmit.
  229. */
  230. struct UNIXMessageWrapper *msg_head;
  231. /**
  232. * Tail of queue of messages to transmit.
  233. */
  234. struct UNIXMessageWrapper *msg_tail;
  235. /**
  236. * Path of our unix domain socket (/tmp/unix-plugin)
  237. */
  238. char *unix_socket_path;
  239. /**
  240. * Function to call about session status changes.
  241. */
  242. GNUNET_TRANSPORT_SessionInfoCallback sic;
  243. /**
  244. * Closure for @e sic.
  245. */
  246. void *sic_cls;
  247. /**
  248. * socket that we transmit all data with
  249. */
  250. struct UNIX_Sock_Info unix_sock;
  251. /**
  252. * Address options in HBO
  253. */
  254. uint32_t myoptions;
  255. /**
  256. * Are we using an abstract UNIX domain socket?
  257. */
  258. int is_abstract;
  259. };
  260. /**
  261. * If a session monitor is attached, notify it about the new
  262. * session state.
  263. *
  264. * @param plugin our plugin
  265. * @param session session that changed state
  266. * @param state new state of the session
  267. */
  268. static void
  269. notify_session_monitor (struct Plugin *plugin,
  270. struct GNUNET_ATS_Session *session,
  271. enum GNUNET_TRANSPORT_SessionState state)
  272. {
  273. struct GNUNET_TRANSPORT_SessionInfo info;
  274. if (NULL == plugin->sic)
  275. return;
  276. memset (&info, 0, sizeof(info));
  277. info.state = state;
  278. info.is_inbound = GNUNET_SYSERR; /* hard to say */
  279. info.num_msg_pending = session->msgs_in_queue;
  280. info.num_bytes_pending = session->bytes_in_queue;
  281. /* info.receive_delay remains zero as this is not supported by UNIX
  282. (cannot selectively not receive from 'some' peer while continuing
  283. to receive from others) */
  284. info.session_timeout = session->timeout;
  285. info.address = session->address;
  286. plugin->sic (plugin->sic_cls, session, &info);
  287. }
  288. /**
  289. * Function called for a quick conversion of the binary address to
  290. * a numeric address. Note that the caller must not free the
  291. * address and that the next call to this function is allowed
  292. * to override the address again.
  293. *
  294. * @param cls closure
  295. * @param addr binary address
  296. * @param addrlen length of the @a addr
  297. * @return string representing the same address
  298. */
  299. static const char *
  300. unix_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
  301. {
  302. static char rbuf[1024];
  303. struct UnixAddress *ua = (struct UnixAddress *) addr;
  304. char *addrstr;
  305. size_t addr_str_len;
  306. unsigned int off;
  307. if ((NULL == addr) || (sizeof(struct UnixAddress) > addrlen))
  308. {
  309. GNUNET_break (0);
  310. return NULL;
  311. }
  312. addrstr = (char *) &ua[1];
  313. addr_str_len = ntohl (ua->addrlen);
  314. if (addr_str_len != addrlen - sizeof(struct UnixAddress))
  315. {
  316. GNUNET_break (0);
  317. return NULL;
  318. }
  319. if ('\0' != addrstr[addr_str_len - 1])
  320. {
  321. GNUNET_break (0);
  322. return NULL;
  323. }
  324. if (strlen (addrstr) + 1 != addr_str_len)
  325. {
  326. GNUNET_break (0);
  327. return NULL;
  328. }
  329. off = 0;
  330. if ('\0' == addrstr[0])
  331. off++;
  332. memset (rbuf, 0, sizeof(rbuf));
  333. GNUNET_snprintf (rbuf,
  334. sizeof(rbuf) - 1,
  335. "%s.%u.%s%.*s",
  336. PLUGIN_NAME,
  337. ntohl (ua->options),
  338. (off == 1) ? "@" : "",
  339. (int) (addr_str_len - off),
  340. &addrstr[off]);
  341. return rbuf;
  342. }
  343. /**
  344. * Functions with this signature are called whenever we need
  345. * to close a session due to a disconnect or failure to
  346. * establish a connection.
  347. *
  348. * @param cls closure with the `struct Plugin *`
  349. * @param session session to close down
  350. * @return #GNUNET_OK on success
  351. */
  352. static int
  353. unix_plugin_session_disconnect (void *cls, struct GNUNET_ATS_Session *session)
  354. {
  355. struct Plugin *plugin = cls;
  356. struct UNIXMessageWrapper *msgw;
  357. struct UNIXMessageWrapper *next;
  358. LOG (GNUNET_ERROR_TYPE_DEBUG,
  359. "Disconnecting session for peer `%s' `%s'\n",
  360. GNUNET_i2s (&session->target),
  361. unix_plugin_address_to_string (NULL,
  362. session->address->address,
  363. session->address->address_length));
  364. plugin->env->session_end (plugin->env->cls, session->address, session);
  365. next = plugin->msg_head;
  366. while (NULL != next)
  367. {
  368. msgw = next;
  369. next = msgw->next;
  370. if (msgw->session != session)
  371. continue;
  372. GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
  373. session->msgs_in_queue--;
  374. GNUNET_assert (session->bytes_in_queue >= msgw->msgsize);
  375. session->bytes_in_queue -= msgw->msgsize;
  376. GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
  377. plugin->bytes_in_queue -= msgw->msgsize;
  378. if (NULL != msgw->cont)
  379. msgw->cont (msgw->cont_cls,
  380. &msgw->session->target,
  381. GNUNET_SYSERR,
  382. msgw->payload,
  383. 0);
  384. GNUNET_free (msgw->msg);
  385. GNUNET_free (msgw);
  386. }
  387. GNUNET_assert (GNUNET_YES ==
  388. GNUNET_CONTAINER_multipeermap_remove (plugin->session_map,
  389. &session->target,
  390. session));
  391. GNUNET_STATISTICS_set (plugin->env->stats,
  392. "# UNIX sessions active",
  393. GNUNET_CONTAINER_multipeermap_size (
  394. plugin->session_map),
  395. GNUNET_NO);
  396. if (NULL != session->timeout_task)
  397. {
  398. GNUNET_SCHEDULER_cancel (session->timeout_task);
  399. session->timeout_task = NULL;
  400. session->timeout = GNUNET_TIME_UNIT_ZERO_ABS;
  401. }
  402. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_DONE);
  403. GNUNET_HELLO_address_free (session->address);
  404. GNUNET_break (0 == session->bytes_in_queue);
  405. GNUNET_break (0 == session->msgs_in_queue);
  406. GNUNET_free (session);
  407. return GNUNET_OK;
  408. }
  409. /**
  410. * Session was idle for too long, so disconnect it
  411. *
  412. * @param cls the `struct GNUNET_ATS_Session *` to disconnect
  413. */
  414. static void
  415. session_timeout (void *cls)
  416. {
  417. struct GNUNET_ATS_Session *session = cls;
  418. struct GNUNET_TIME_Relative left;
  419. session->timeout_task = NULL;
  420. left = GNUNET_TIME_absolute_get_remaining (session->timeout);
  421. if (0 != left.rel_value_us)
  422. {
  423. /* not actually our turn yet, but let's at least update
  424. the monitor, it may think we're about to die ... */
  425. notify_session_monitor (session->plugin,
  426. session,
  427. GNUNET_TRANSPORT_SS_UPDATE);
  428. session->timeout_task =
  429. GNUNET_SCHEDULER_add_delayed (left, &session_timeout, session);
  430. return;
  431. }
  432. LOG (GNUNET_ERROR_TYPE_DEBUG,
  433. "Session %p was idle for %s, disconnecting\n",
  434. session,
  435. GNUNET_STRINGS_relative_time_to_string (
  436. GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
  437. GNUNET_YES));
  438. unix_plugin_session_disconnect (session->plugin, session);
  439. }
  440. /**
  441. * Increment session timeout due to activity. We do not immediately
  442. * notify the monitor here as that might generate excessive
  443. * signalling.
  444. *
  445. * @param session session for which the timeout should be rescheduled
  446. */
  447. static void
  448. reschedule_session_timeout (struct GNUNET_ATS_Session *session)
  449. {
  450. GNUNET_assert (NULL != session->timeout_task);
  451. session->timeout =
  452. GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
  453. }
  454. /**
  455. * Convert unix path to a `struct sockaddr_un *`
  456. *
  457. * @param unixpath path to convert
  458. * @param[out] sock_len set to the length of the address
  459. * @return converted unix path
  460. */
  461. static struct sockaddr_un *
  462. unix_address_to_sockaddr (const char *unixpath, socklen_t *sock_len)
  463. {
  464. struct sockaddr_un *un;
  465. size_t slen;
  466. GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
  467. un = GNUNET_new (struct sockaddr_un);
  468. un->sun_family = AF_UNIX;
  469. slen = strlen (unixpath);
  470. if (slen >= sizeof(un->sun_path))
  471. slen = sizeof(un->sun_path) - 1;
  472. GNUNET_memcpy (un->sun_path, unixpath, slen);
  473. un->sun_path[slen] = '\0';
  474. slen = sizeof(struct sockaddr_un);
  475. #if HAVE_SOCKADDR_UN_SUN_LEN
  476. un->sun_len = (u_char) slen;
  477. #endif
  478. (*sock_len) = slen;
  479. return un;
  480. }
  481. /**
  482. * Closure to #lookup_session_it().
  483. */
  484. struct LookupCtx
  485. {
  486. /**
  487. * Location to store the session, if found.
  488. */
  489. struct GNUNET_ATS_Session *res;
  490. /**
  491. * Address we are looking for.
  492. */
  493. const struct GNUNET_HELLO_Address *address;
  494. };
  495. /**
  496. * Function called to find a session by address.
  497. *
  498. * @param cls the `struct LookupCtx *`
  499. * @param key peer we are looking for (unused)
  500. * @param value a session
  501. * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
  502. */
  503. static int
  504. lookup_session_it (void *cls,
  505. const struct GNUNET_PeerIdentity *key,
  506. void *value)
  507. {
  508. struct LookupCtx *lctx = cls;
  509. struct GNUNET_ATS_Session *session = value;
  510. if (0 == GNUNET_HELLO_address_cmp (lctx->address, session->address))
  511. {
  512. lctx->res = session;
  513. return GNUNET_NO;
  514. }
  515. return GNUNET_YES;
  516. }
  517. /**
  518. * Find an existing session by address.
  519. *
  520. * @param plugin the plugin
  521. * @param address the address to find
  522. * @return NULL if session was not found
  523. */
  524. static struct GNUNET_ATS_Session *
  525. lookup_session (struct Plugin *plugin,
  526. const struct GNUNET_HELLO_Address *address)
  527. {
  528. struct LookupCtx lctx;
  529. lctx.address = address;
  530. lctx.res = NULL;
  531. GNUNET_CONTAINER_multipeermap_get_multiple (plugin->session_map,
  532. &address->peer,
  533. &lookup_session_it,
  534. &lctx);
  535. return lctx.res;
  536. }
  537. /**
  538. * Function that is called to get the keepalive factor.
  539. * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
  540. * calculate the interval between keepalive packets.
  541. *
  542. * @param cls closure with the `struct Plugin`
  543. * @return keepalive factor
  544. */
  545. static unsigned int
  546. unix_plugin_query_keepalive_factor (void *cls)
  547. {
  548. return 3;
  549. }
  550. /**
  551. * Actually send out the message, assume we've got the address and
  552. * send_handle squared away!
  553. *
  554. * @param cls closure
  555. * @param send_handle which handle to send message on
  556. * @param target who should receive this message (ignored by UNIX)
  557. * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
  558. * @param msgbuf_size the size of the @a msgbuf to send
  559. * @param priority how important is the message (ignored by UNIX)
  560. * @param timeout when should we time out (give up) if we can not transmit?
  561. * @param addr the addr to send the message to, needs to be a sockaddr for us
  562. * @param addrlen the len of @a addr
  563. * @param payload bytes payload to send
  564. * @param cont continuation to call once the message has
  565. * been transmitted (or if the transport is ready
  566. * for the next transmission call; or if the
  567. * peer disconnected...)
  568. * @param cont_cls closure for @a cont
  569. * @return on success the number of bytes written, RETRY for retry, -1 on errors
  570. */
  571. static ssize_t
  572. unix_real_send (void *cls,
  573. struct GNUNET_NETWORK_Handle *send_handle,
  574. const struct GNUNET_PeerIdentity *target,
  575. const char *msgbuf,
  576. size_t msgbuf_size,
  577. unsigned int priority,
  578. struct GNUNET_TIME_Absolute timeout,
  579. const struct UnixAddress *addr,
  580. size_t addrlen,
  581. size_t payload,
  582. GNUNET_TRANSPORT_TransmitContinuation cont,
  583. void *cont_cls)
  584. {
  585. struct Plugin *plugin = cls;
  586. ssize_t sent;
  587. struct sockaddr_un *un;
  588. socklen_t un_len;
  589. const char *unixpath;
  590. if (NULL == send_handle)
  591. {
  592. GNUNET_break (0); /* We do not have a send handle */
  593. return GNUNET_SYSERR;
  594. }
  595. if ((NULL == addr) || (0 == addrlen))
  596. {
  597. GNUNET_break (0); /* Can never send if we don't have an address */
  598. return GNUNET_SYSERR;
  599. }
  600. /* Prepare address */
  601. unixpath = (const char *) &addr[1];
  602. if (NULL == (un = unix_address_to_sockaddr (unixpath, &un_len)))
  603. {
  604. GNUNET_break (0);
  605. return -1;
  606. }
  607. if ((GNUNET_YES == plugin->is_abstract) &&
  608. (0 != (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS & ntohl (addr->options))))
  609. {
  610. un->sun_path[0] = '\0';
  611. }
  612. resend:
  613. /* Send the data */
  614. sent = GNUNET_NETWORK_socket_sendto (send_handle,
  615. msgbuf,
  616. msgbuf_size,
  617. (const struct sockaddr *) un,
  618. un_len);
  619. if (GNUNET_SYSERR == sent)
  620. {
  621. if ((EAGAIN == errno) || (ENOBUFS == errno))
  622. {
  623. GNUNET_free (un);
  624. return RETRY; /* We have to retry later */
  625. }
  626. if (EMSGSIZE == errno)
  627. {
  628. socklen_t size = 0;
  629. socklen_t len = sizeof(size);
  630. GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle *)
  631. send_handle,
  632. SOL_SOCKET,
  633. SO_SNDBUF,
  634. &size,
  635. &len);
  636. if (size < msgbuf_size)
  637. {
  638. LOG (GNUNET_ERROR_TYPE_DEBUG,
  639. "Trying to increase socket buffer size from %u to %u for message size %u\n",
  640. (unsigned int) size,
  641. (unsigned int) ((msgbuf_size / 1000) + 2) * 1000,
  642. (unsigned int) msgbuf_size);
  643. size = ((msgbuf_size / 1000) + 2) * 1000;
  644. if (GNUNET_OK ==
  645. GNUNET_NETWORK_socket_setsockopt ((struct GNUNET_NETWORK_Handle *)
  646. send_handle,
  647. SOL_SOCKET,
  648. SO_SNDBUF,
  649. &size,
  650. sizeof(size)))
  651. goto resend; /* Increased buffer size, retry sending */
  652. else
  653. {
  654. /* Could not increase buffer size: error, no retry */
  655. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
  656. GNUNET_free (un);
  657. return GNUNET_SYSERR;
  658. }
  659. }
  660. else
  661. {
  662. /* Buffer is bigger than message: error, no retry
  663. * This should never happen!*/
  664. GNUNET_break (0);
  665. GNUNET_free (un);
  666. return GNUNET_SYSERR;
  667. }
  668. }
  669. }
  670. LOG (GNUNET_ERROR_TYPE_DEBUG,
  671. "UNIX transmitted %u-byte message to %s (%d: %s)\n",
  672. (unsigned int) msgbuf_size,
  673. GNUNET_a2s ((const struct sockaddr *) un, un_len),
  674. (int) sent,
  675. (sent < 0) ? strerror (errno) : "ok");
  676. GNUNET_free (un);
  677. return sent;
  678. }
  679. /**
  680. * Function obtain the network type for a session
  681. *
  682. * @param cls closure ('struct Plugin*')
  683. * @param session the session
  684. * @return the network type in HBO or #GNUNET_SYSERR
  685. */
  686. static enum GNUNET_NetworkType
  687. unix_plugin_get_network (void *cls, struct GNUNET_ATS_Session *session)
  688. {
  689. GNUNET_assert (NULL != session);
  690. return GNUNET_NT_LOOPBACK;
  691. }
  692. /**
  693. * Function obtain the network type for a session
  694. *
  695. * @param cls closure (`struct Plugin *`)
  696. * @param address the address
  697. * @return the network type
  698. */
  699. static enum GNUNET_NetworkType
  700. unix_plugin_get_network_for_address (void *cls,
  701. const struct GNUNET_HELLO_Address *address)
  702. {
  703. return GNUNET_NT_LOOPBACK;
  704. }
  705. /**
  706. * Creates a new outbound session the transport service will use to send data to the
  707. * peer
  708. *
  709. * @param cls the plugin
  710. * @param address the address
  711. * @return the session or NULL of max connections exceeded
  712. */
  713. static struct GNUNET_ATS_Session *
  714. unix_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address)
  715. {
  716. struct Plugin *plugin = cls;
  717. struct GNUNET_ATS_Session *session;
  718. struct UnixAddress *ua;
  719. char *addrstr;
  720. uint32_t addr_str_len;
  721. uint32_t addr_option;
  722. ua = (struct UnixAddress *) address->address;
  723. if ((NULL == address->address) || (0 == address->address_length) ||
  724. (sizeof(struct UnixAddress) > address->address_length))
  725. {
  726. GNUNET_break (0);
  727. return NULL;
  728. }
  729. addrstr = (char *) &ua[1];
  730. addr_str_len = ntohl (ua->addrlen);
  731. addr_option = ntohl (ua->options);
  732. if ((0 != (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS & addr_option)) &&
  733. (GNUNET_NO == plugin->is_abstract))
  734. {
  735. return NULL;
  736. }
  737. if (addr_str_len != address->address_length - sizeof(struct UnixAddress))
  738. {
  739. return NULL; /* This can be a legacy address */
  740. }
  741. if ('\0' != addrstr[addr_str_len - 1])
  742. {
  743. GNUNET_break (0);
  744. return NULL;
  745. }
  746. if (strlen (addrstr) + 1 != addr_str_len)
  747. {
  748. GNUNET_break (0);
  749. return NULL;
  750. }
  751. /* Check if a session for this address already exists */
  752. if (NULL != (session = lookup_session (plugin, address)))
  753. {
  754. LOG (GNUNET_ERROR_TYPE_DEBUG,
  755. "Found existing session %p for address `%s'\n",
  756. session,
  757. unix_plugin_address_to_string (NULL,
  758. address->address,
  759. address->address_length));
  760. return session;
  761. }
  762. /* create a new session */
  763. session = GNUNET_new (struct GNUNET_ATS_Session);
  764. session->target = address->peer;
  765. session->address = GNUNET_HELLO_address_copy (address);
  766. session->plugin = plugin;
  767. session->timeout =
  768. GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
  769. session->timeout_task =
  770. GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
  771. &session_timeout,
  772. session);
  773. LOG (GNUNET_ERROR_TYPE_DEBUG,
  774. "Creating a new session %p for address `%s'\n",
  775. session,
  776. unix_plugin_address_to_string (NULL,
  777. address->address,
  778. address->address_length));
  779. (void) GNUNET_CONTAINER_multipeermap_put (
  780. plugin->session_map,
  781. &address->peer,
  782. session,
  783. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  784. GNUNET_STATISTICS_set (plugin->env->stats,
  785. "# UNIX sessions active",
  786. GNUNET_CONTAINER_multipeermap_size (
  787. plugin->session_map),
  788. GNUNET_NO);
  789. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
  790. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
  791. return session;
  792. }
  793. /**
  794. * Function that will be called whenever the transport service wants
  795. * to notify the plugin that a session is still active and in use and
  796. * therefore the session timeout for this session has to be updated
  797. *
  798. * @param cls closure with the `struct Plugin *`
  799. * @param peer which peer was the session for
  800. * @param session which session is being updated
  801. */
  802. static void
  803. unix_plugin_update_session_timeout (void *cls,
  804. const struct GNUNET_PeerIdentity *peer,
  805. struct GNUNET_ATS_Session *session)
  806. {
  807. struct Plugin *plugin = cls;
  808. if (GNUNET_OK !=
  809. GNUNET_CONTAINER_multipeermap_contains_value (plugin->session_map,
  810. &session->target,
  811. session))
  812. {
  813. GNUNET_break (0);
  814. return;
  815. }
  816. reschedule_session_timeout (session);
  817. }
  818. /**
  819. * Demultiplexer for UNIX messages
  820. *
  821. * @param plugin the main plugin for this transport
  822. * @param sender from which peer the message was received
  823. * @param currhdr pointer to the header of the message
  824. * @param ua address to look for
  825. * @param ua_len length of the address @a ua
  826. */
  827. static void
  828. unix_demultiplexer (struct Plugin *plugin,
  829. struct GNUNET_PeerIdentity *sender,
  830. const struct GNUNET_MessageHeader *currhdr,
  831. const struct UnixAddress *ua,
  832. size_t ua_len)
  833. {
  834. struct GNUNET_ATS_Session *session;
  835. struct GNUNET_HELLO_Address *address;
  836. GNUNET_assert (ua_len >= sizeof(struct UnixAddress));
  837. LOG (GNUNET_ERROR_TYPE_DEBUG,
  838. "Received message from %s\n",
  839. unix_plugin_address_to_string (NULL, ua, ua_len));
  840. GNUNET_STATISTICS_update (plugin->env->stats,
  841. "# bytes received via UNIX",
  842. ntohs (currhdr->size),
  843. GNUNET_NO);
  844. /* Look for existing session */
  845. address = GNUNET_HELLO_address_allocate (
  846. sender,
  847. PLUGIN_NAME,
  848. ua,
  849. ua_len,
  850. GNUNET_HELLO_ADDRESS_INFO_NONE); /* UNIX does not have "inbound" sessions */
  851. session = lookup_session (plugin, address);
  852. if (NULL == session)
  853. {
  854. session = unix_plugin_get_session (plugin, address);
  855. /* Notify transport and ATS about new inbound session */
  856. plugin->env->session_start (NULL,
  857. session->address,
  858. session,
  859. GNUNET_NT_LOOPBACK);
  860. }
  861. else
  862. {
  863. reschedule_session_timeout (session);
  864. }
  865. GNUNET_HELLO_address_free (address);
  866. plugin->env->receive (plugin->env->cls, session->address, session, currhdr);
  867. }
  868. /**
  869. * Read from UNIX domain socket (it is ready).
  870. *
  871. * @param plugin the plugin
  872. */
  873. static void
  874. unix_plugin_do_read (struct Plugin *plugin)
  875. {
  876. char buf[65536] GNUNET_ALIGN;
  877. struct UnixAddress *ua;
  878. struct UNIXMessage *msg;
  879. struct GNUNET_PeerIdentity sender;
  880. struct sockaddr_un un;
  881. socklen_t addrlen;
  882. ssize_t ret;
  883. int offset;
  884. int tsize;
  885. int is_abstract;
  886. char *msgbuf;
  887. const struct GNUNET_MessageHeader *currhdr;
  888. uint16_t csize;
  889. size_t ua_len;
  890. addrlen = sizeof(un);
  891. memset (&un, 0, sizeof(un));
  892. ret = GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc,
  893. buf,
  894. sizeof(buf),
  895. (struct sockaddr *) &un,
  896. &addrlen);
  897. if ((GNUNET_SYSERR == ret) && ((errno == EAGAIN) || (errno == ENOBUFS)))
  898. return;
  899. if (GNUNET_SYSERR == ret)
  900. {
  901. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
  902. return;
  903. }
  904. else
  905. {
  906. LOG (GNUNET_ERROR_TYPE_DEBUG,
  907. "Read %d bytes from socket %s\n",
  908. (int) ret,
  909. un.sun_path);
  910. }
  911. GNUNET_assert (AF_UNIX == (un.sun_family));
  912. is_abstract = GNUNET_NO;
  913. if ('\0' == un.sun_path[0])
  914. {
  915. un.sun_path[0] = '@';
  916. is_abstract = GNUNET_YES;
  917. }
  918. ua_len = sizeof(struct UnixAddress) + strlen (un.sun_path) + 1;
  919. ua = GNUNET_malloc (ua_len);
  920. ua->addrlen = htonl (strlen (&un.sun_path[0]) + 1);
  921. GNUNET_memcpy (&ua[1], &un.sun_path[0], strlen (un.sun_path) + 1);
  922. if (is_abstract)
  923. ua->options = htonl (UNIX_OPTIONS_USE_ABSTRACT_SOCKETS);
  924. else
  925. ua->options = htonl (UNIX_OPTIONS_NONE);
  926. msg = (struct UNIXMessage *) buf;
  927. csize = ntohs (msg->header.size);
  928. if ((csize < sizeof(struct UNIXMessage)) || (csize > ret))
  929. {
  930. GNUNET_break_op (0);
  931. GNUNET_free (ua);
  932. return;
  933. }
  934. msgbuf = (char *) &msg[1];
  935. GNUNET_memcpy (&sender, &msg->sender, sizeof(struct GNUNET_PeerIdentity));
  936. offset = 0;
  937. tsize = csize - sizeof(struct UNIXMessage);
  938. while (offset + sizeof(struct GNUNET_MessageHeader) <= tsize)
  939. {
  940. currhdr = (struct GNUNET_MessageHeader *) &msgbuf[offset];
  941. csize = ntohs (currhdr->size);
  942. if ((csize < sizeof(struct GNUNET_MessageHeader)) ||
  943. (csize > tsize - offset))
  944. {
  945. GNUNET_break_op (0);
  946. break;
  947. }
  948. unix_demultiplexer (plugin, &sender, currhdr, ua, ua_len);
  949. offset += csize;
  950. }
  951. GNUNET_free (ua);
  952. }
  953. /**
  954. * Write to UNIX domain socket (it is ready).
  955. *
  956. * @param plugin handle to the plugin
  957. */
  958. static void
  959. unix_plugin_do_write (struct Plugin *plugin)
  960. {
  961. ssize_t sent = 0;
  962. struct UNIXMessageWrapper *msgw;
  963. struct GNUNET_ATS_Session *session;
  964. int did_delete;
  965. session = NULL;
  966. did_delete = GNUNET_NO;
  967. while (NULL != (msgw = plugin->msg_head))
  968. {
  969. if (GNUNET_TIME_absolute_get_remaining (msgw->timeout).rel_value_us > 0)
  970. break; /* Message is ready for sending */
  971. /* Message has a timeout */
  972. did_delete = GNUNET_YES;
  973. LOG (GNUNET_ERROR_TYPE_DEBUG,
  974. "Timeout for message with %u bytes \n",
  975. (unsigned int) msgw->msgsize);
  976. GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
  977. session = msgw->session;
  978. session->msgs_in_queue--;
  979. GNUNET_assert (session->bytes_in_queue >= msgw->msgsize);
  980. session->bytes_in_queue -= msgw->msgsize;
  981. GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
  982. plugin->bytes_in_queue -= msgw->msgsize;
  983. GNUNET_STATISTICS_set (plugin->env->stats,
  984. "# bytes currently in UNIX buffers",
  985. plugin->bytes_in_queue,
  986. GNUNET_NO);
  987. GNUNET_STATISTICS_update (plugin->env->stats,
  988. "# UNIX bytes discarded",
  989. msgw->msgsize,
  990. GNUNET_NO);
  991. if (NULL != msgw->cont)
  992. msgw->cont (msgw->cont_cls,
  993. &msgw->session->target,
  994. GNUNET_SYSERR,
  995. msgw->payload,
  996. 0);
  997. GNUNET_free (msgw->msg);
  998. GNUNET_free (msgw);
  999. }
  1000. if (NULL == msgw)
  1001. {
  1002. if (GNUNET_YES == did_delete)
  1003. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
  1004. return; /* Nothing to send at the moment */
  1005. }
  1006. session = msgw->session;
  1007. sent = unix_real_send (plugin,
  1008. plugin->unix_sock.desc,
  1009. &session->target,
  1010. (const char *) msgw->msg,
  1011. msgw->msgsize,
  1012. msgw->priority,
  1013. msgw->timeout,
  1014. msgw->session->address->address,
  1015. msgw->session->address->address_length,
  1016. msgw->payload,
  1017. msgw->cont,
  1018. msgw->cont_cls);
  1019. if (RETRY == sent)
  1020. {
  1021. GNUNET_STATISTICS_update (plugin->env->stats,
  1022. "# UNIX retry attempts",
  1023. 1,
  1024. GNUNET_NO);
  1025. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
  1026. return;
  1027. }
  1028. GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
  1029. session->msgs_in_queue--;
  1030. GNUNET_assert (session->bytes_in_queue >= msgw->msgsize);
  1031. session->bytes_in_queue -= msgw->msgsize;
  1032. GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
  1033. plugin->bytes_in_queue -= msgw->msgsize;
  1034. GNUNET_STATISTICS_set (plugin->env->stats,
  1035. "# bytes currently in UNIX buffers",
  1036. plugin->bytes_in_queue,
  1037. GNUNET_NO);
  1038. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
  1039. if (GNUNET_SYSERR == sent)
  1040. {
  1041. /* failed and no retry */
  1042. if (NULL != msgw->cont)
  1043. msgw->cont (msgw->cont_cls,
  1044. &msgw->session->target,
  1045. GNUNET_SYSERR,
  1046. msgw->payload,
  1047. 0);
  1048. GNUNET_STATISTICS_update (plugin->env->stats,
  1049. "# UNIX bytes discarded",
  1050. msgw->msgsize,
  1051. GNUNET_NO);
  1052. GNUNET_free (msgw->msg);
  1053. GNUNET_free (msgw);
  1054. return;
  1055. }
  1056. /* successfully sent bytes */
  1057. GNUNET_break (sent > 0);
  1058. GNUNET_STATISTICS_update (plugin->env->stats,
  1059. "# bytes transmitted via UNIX",
  1060. msgw->msgsize,
  1061. GNUNET_NO);
  1062. if (NULL != msgw->cont)
  1063. msgw->cont (msgw->cont_cls,
  1064. &msgw->session->target,
  1065. GNUNET_OK,
  1066. msgw->payload,
  1067. msgw->msgsize);
  1068. GNUNET_free (msgw->msg);
  1069. GNUNET_free (msgw);
  1070. }
  1071. /**
  1072. * We have been notified that our socket has something to read.
  1073. * Then reschedule this function to be called again once more is available.
  1074. *
  1075. * @param cls the plugin handle
  1076. */
  1077. static void
  1078. unix_plugin_select_read (void *cls)
  1079. {
  1080. struct Plugin *plugin = cls;
  1081. const struct GNUNET_SCHEDULER_TaskContext *tc;
  1082. plugin->read_task = NULL;
  1083. tc = GNUNET_SCHEDULER_get_task_context ();
  1084. if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
  1085. unix_plugin_do_read (plugin);
  1086. plugin->read_task =
  1087. GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  1088. plugin->unix_sock.desc,
  1089. &unix_plugin_select_read,
  1090. plugin);
  1091. }
  1092. /**
  1093. * We have been notified that our socket is ready to write.
  1094. * Then reschedule this function to be called again once more is available.
  1095. *
  1096. * @param cls the plugin handle
  1097. */
  1098. static void
  1099. unix_plugin_select_write (void *cls)
  1100. {
  1101. struct Plugin *plugin = cls;
  1102. const struct GNUNET_SCHEDULER_TaskContext *tc;
  1103. plugin->write_task = NULL;
  1104. tc = GNUNET_SCHEDULER_get_task_context ();
  1105. if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
  1106. unix_plugin_do_write (plugin);
  1107. if (NULL == plugin->msg_head)
  1108. return; /* write queue empty */
  1109. plugin->write_task =
  1110. GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
  1111. plugin->unix_sock.desc,
  1112. &unix_plugin_select_write,
  1113. plugin);
  1114. }
  1115. /**
  1116. * Function that can be used by the transport service to transmit
  1117. * a message using the plugin. Note that in the case of a
  1118. * peer disconnecting, the continuation MUST be called
  1119. * prior to the disconnect notification itself. This function
  1120. * will be called with this peer's HELLO message to initiate
  1121. * a fresh connection to another peer.
  1122. *
  1123. * @param cls closure
  1124. * @param session which session must be used
  1125. * @param msgbuf the message to transmit
  1126. * @param msgbuf_size number of bytes in @a msgbuf
  1127. * @param priority how important is the message (most plugins will
  1128. * ignore message priority and just FIFO)
  1129. * @param to how long to wait at most for the transmission (does not
  1130. * require plugins to discard the message after the timeout,
  1131. * just advisory for the desired delay; most plugins will ignore
  1132. * this as well)
  1133. * @param cont continuation to call once the message has
  1134. * been transmitted (or if the transport is ready
  1135. * for the next transmission call; or if the
  1136. * peer disconnected...); can be NULL
  1137. * @param cont_cls closure for @a cont
  1138. * @return number of bytes used (on the physical network, with overheads);
  1139. * -1 on hard errors (i.e. address invalid); 0 is a legal value
  1140. * and does NOT mean that the message was not transmitted (DV)
  1141. */
  1142. static ssize_t
  1143. unix_plugin_send (void *cls,
  1144. struct GNUNET_ATS_Session *session,
  1145. const char *msgbuf,
  1146. size_t msgbuf_size,
  1147. unsigned int priority,
  1148. struct GNUNET_TIME_Relative to,
  1149. GNUNET_TRANSPORT_TransmitContinuation cont,
  1150. void *cont_cls)
  1151. {
  1152. struct Plugin *plugin = cls;
  1153. struct UNIXMessageWrapper *wrapper;
  1154. struct UNIXMessage *message;
  1155. int ssize;
  1156. if (GNUNET_OK !=
  1157. GNUNET_CONTAINER_multipeermap_contains_value (plugin->session_map,
  1158. &session->target,
  1159. session))
  1160. {
  1161. LOG (GNUNET_ERROR_TYPE_ERROR,
  1162. "Invalid session for peer `%s' `%s'\n",
  1163. GNUNET_i2s (&session->target),
  1164. unix_plugin_address_to_string (NULL,
  1165. session->address->address,
  1166. session->address->address_length));
  1167. GNUNET_break (0);
  1168. return GNUNET_SYSERR;
  1169. }
  1170. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1171. "Sending %u bytes with session for peer `%s' `%s'\n",
  1172. msgbuf_size,
  1173. GNUNET_i2s (&session->target),
  1174. unix_plugin_address_to_string (NULL,
  1175. session->address->address,
  1176. session->address->address_length));
  1177. ssize = sizeof(struct UNIXMessage) + msgbuf_size;
  1178. message = GNUNET_malloc (sizeof(struct UNIXMessage) + msgbuf_size);
  1179. message->header.size = htons (ssize);
  1180. message->header.type = htons (0);
  1181. GNUNET_memcpy (&message->sender,
  1182. plugin->env->my_identity,
  1183. sizeof(struct GNUNET_PeerIdentity));
  1184. GNUNET_memcpy (&message[1], msgbuf, msgbuf_size);
  1185. wrapper = GNUNET_new (struct UNIXMessageWrapper);
  1186. wrapper->msg = message;
  1187. wrapper->msgsize = ssize;
  1188. wrapper->payload = msgbuf_size;
  1189. wrapper->priority = priority;
  1190. wrapper->timeout = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), to);
  1191. wrapper->cont = cont;
  1192. wrapper->cont_cls = cont_cls;
  1193. wrapper->session = session;
  1194. GNUNET_CONTAINER_DLL_insert_tail (plugin->msg_head,
  1195. plugin->msg_tail,
  1196. wrapper);
  1197. plugin->bytes_in_queue += ssize;
  1198. session->bytes_in_queue += ssize;
  1199. session->msgs_in_queue++;
  1200. GNUNET_STATISTICS_set (plugin->env->stats,
  1201. "# bytes currently in UNIX buffers",
  1202. plugin->bytes_in_queue,
  1203. GNUNET_NO);
  1204. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UPDATE);
  1205. if (NULL == plugin->write_task)
  1206. plugin->write_task =
  1207. GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
  1208. plugin->unix_sock.desc,
  1209. &unix_plugin_select_write,
  1210. plugin);
  1211. return ssize;
  1212. }
  1213. /**
  1214. * Create a slew of UNIX sockets. If possible, use IPv6 and IPv4.
  1215. *
  1216. * @param cls closure for server start, should be a `struct Plugin *`
  1217. * @return number of sockets created or #GNUNET_SYSERR on error
  1218. */
  1219. static int
  1220. unix_transport_server_start (void *cls)
  1221. {
  1222. struct Plugin *plugin = cls;
  1223. struct sockaddr_un *un;
  1224. socklen_t un_len;
  1225. un = unix_address_to_sockaddr (plugin->unix_socket_path, &un_len);
  1226. if (GNUNET_YES == plugin->is_abstract)
  1227. {
  1228. plugin->unix_socket_path[0] = '@';
  1229. un->sun_path[0] = '\0';
  1230. }
  1231. plugin->unix_sock.desc =
  1232. GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
  1233. if (NULL == plugin->unix_sock.desc)
  1234. {
  1235. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
  1236. GNUNET_free (un);
  1237. return GNUNET_SYSERR;
  1238. }
  1239. if ('\0' != un->sun_path[0])
  1240. {
  1241. if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (un->sun_path))
  1242. {
  1243. LOG (GNUNET_ERROR_TYPE_ERROR,
  1244. _ ("Cannot create path to `%s'\n"),
  1245. un->sun_path);
  1246. GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
  1247. plugin->unix_sock.desc = NULL;
  1248. GNUNET_free (un);
  1249. return GNUNET_SYSERR;
  1250. }
  1251. }
  1252. if (GNUNET_OK != GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc,
  1253. (const struct sockaddr *) un,
  1254. un_len))
  1255. {
  1256. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
  1257. LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Cannot bind to `%s'\n"), un->sun_path);
  1258. GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
  1259. plugin->unix_sock.desc = NULL;
  1260. GNUNET_free (un);
  1261. return GNUNET_SYSERR;
  1262. }
  1263. LOG (GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", plugin->unix_socket_path);
  1264. plugin->read_task =
  1265. GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  1266. plugin->unix_sock.desc,
  1267. &unix_plugin_select_read,
  1268. plugin);
  1269. GNUNET_free (un);
  1270. return 1;
  1271. }
  1272. /**
  1273. * Function that will be called to check if a binary address for this
  1274. * plugin is well-formed and corresponds to an address for THIS peer
  1275. * (as per our configuration). Naturally, if absolutely necessary,
  1276. * plugins can be a bit conservative in their answer, but in general
  1277. * plugins should make sure that the address does not redirect
  1278. * traffic to a 3rd party that might try to man-in-the-middle our
  1279. * traffic.
  1280. *
  1281. * @param cls closure, should be our handle to the Plugin
  1282. * @param addr pointer to the address
  1283. * @param addrlen length of @a addr
  1284. * @return #GNUNET_OK if this is a plausible address for this peer
  1285. * and transport, #GNUNET_SYSERR if not
  1286. *
  1287. */
  1288. static int
  1289. unix_plugin_check_address (void *cls, const void *addr, size_t addrlen)
  1290. {
  1291. struct Plugin *plugin = cls;
  1292. const struct UnixAddress *ua = addr;
  1293. char *addrstr;
  1294. size_t addr_str_len;
  1295. if ((NULL == addr) || (0 == addrlen) ||
  1296. (sizeof(struct UnixAddress) > addrlen))
  1297. {
  1298. GNUNET_break (0);
  1299. return GNUNET_SYSERR;
  1300. }
  1301. addrstr = (char *) &ua[1];
  1302. addr_str_len = ntohl (ua->addrlen);
  1303. if ('\0' != addrstr[addr_str_len - 1])
  1304. {
  1305. GNUNET_break (0);
  1306. return GNUNET_SYSERR;
  1307. }
  1308. if (strlen (addrstr) + 1 != addr_str_len)
  1309. {
  1310. GNUNET_break (0);
  1311. return GNUNET_SYSERR;
  1312. }
  1313. if (0 == strcmp (plugin->unix_socket_path, addrstr))
  1314. return GNUNET_OK;
  1315. return GNUNET_SYSERR;
  1316. }
  1317. /**
  1318. * Convert the transports address to a nice, human-readable
  1319. * format.
  1320. *
  1321. * @param cls closure
  1322. * @param type name of the transport that generated the address
  1323. * @param addr one of the addresses of the host, NULL for the last address
  1324. * the specific address format depends on the transport
  1325. * @param addrlen length of the @a addr
  1326. * @param numeric should (IP) addresses be displayed in numeric form?
  1327. * @param timeout after how long should we give up?
  1328. * @param asc function to call on each string
  1329. * @param asc_cls closure for @a asc
  1330. */
  1331. static void
  1332. unix_plugin_address_pretty_printer (void *cls,
  1333. const char *type,
  1334. const void *addr,
  1335. size_t addrlen,
  1336. int numeric,
  1337. struct GNUNET_TIME_Relative timeout,
  1338. GNUNET_TRANSPORT_AddressStringCallback asc,
  1339. void *asc_cls)
  1340. {
  1341. const char *ret;
  1342. if ((NULL != addr) && (addrlen > 0))
  1343. ret = unix_plugin_address_to_string (NULL, addr, addrlen);
  1344. else
  1345. ret = NULL;
  1346. asc (asc_cls, ret, (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
  1347. asc (asc_cls, NULL, GNUNET_OK);
  1348. }
  1349. /**
  1350. * Function called to convert a string address to
  1351. * a binary address.
  1352. *
  1353. * @param cls closure (`struct Plugin *`)
  1354. * @param addr string address
  1355. * @param addrlen length of the @a addr (strlen(addr) + '\0')
  1356. * @param buf location to store the buffer
  1357. * If the function returns #GNUNET_SYSERR, its contents are undefined.
  1358. * @param added length of created address
  1359. * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
  1360. */
  1361. static int
  1362. unix_plugin_string_to_address (void *cls,
  1363. const char *addr,
  1364. uint16_t addrlen,
  1365. void **buf,
  1366. size_t *added)
  1367. {
  1368. struct UnixAddress *ua;
  1369. char *address;
  1370. char *plugin;
  1371. char *optionstr;
  1372. uint32_t options;
  1373. size_t ua_size;
  1374. /* Format unix.options.address */
  1375. address = NULL;
  1376. plugin = NULL;
  1377. optionstr = NULL;
  1378. if ((NULL == addr) || (addrlen == 0))
  1379. {
  1380. GNUNET_break (0);
  1381. return GNUNET_SYSERR;
  1382. }
  1383. if ('\0' != addr[addrlen - 1])
  1384. {
  1385. GNUNET_break (0);
  1386. return GNUNET_SYSERR;
  1387. }
  1388. if (strlen (addr) != addrlen - 1)
  1389. {
  1390. GNUNET_break (0);
  1391. return GNUNET_SYSERR;
  1392. }
  1393. plugin = GNUNET_strdup (addr);
  1394. optionstr = strchr (plugin, '.');
  1395. if (NULL == optionstr)
  1396. {
  1397. GNUNET_break (0);
  1398. GNUNET_free (plugin);
  1399. return GNUNET_SYSERR;
  1400. }
  1401. optionstr[0] = '\0';
  1402. optionstr++;
  1403. options = atol (optionstr);
  1404. address = strchr (optionstr, '.');
  1405. if (NULL == address)
  1406. {
  1407. GNUNET_break (0);
  1408. GNUNET_free (plugin);
  1409. return GNUNET_SYSERR;
  1410. }
  1411. address[0] = '\0';
  1412. address++;
  1413. if (0 != strcmp (plugin, PLUGIN_NAME))
  1414. {
  1415. GNUNET_break (0);
  1416. GNUNET_free (plugin);
  1417. return GNUNET_SYSERR;
  1418. }
  1419. ua_size = sizeof(struct UnixAddress) + strlen (address) + 1;
  1420. ua = GNUNET_malloc (ua_size);
  1421. ua->options = htonl (options);
  1422. ua->addrlen = htonl (strlen (address) + 1);
  1423. GNUNET_memcpy (&ua[1], address, strlen (address) + 1);
  1424. GNUNET_free (plugin);
  1425. (*buf) = ua;
  1426. (*added) = ua_size;
  1427. return GNUNET_OK;
  1428. }
  1429. /**
  1430. * Notify transport service about address
  1431. *
  1432. * @param cls the plugin
  1433. */
  1434. static void
  1435. address_notification (void *cls)
  1436. {
  1437. struct Plugin *plugin = cls;
  1438. struct GNUNET_HELLO_Address *address;
  1439. size_t len;
  1440. struct UnixAddress *ua;
  1441. char *unix_path;
  1442. len = sizeof(struct UnixAddress) + strlen (plugin->unix_socket_path) + 1;
  1443. ua = GNUNET_malloc (len);
  1444. ua->options = htonl (plugin->myoptions);
  1445. ua->addrlen = htonl (strlen (plugin->unix_socket_path) + 1);
  1446. unix_path = (char *) &ua[1];
  1447. GNUNET_memcpy (unix_path,
  1448. plugin->unix_socket_path,
  1449. strlen (plugin->unix_socket_path) + 1);
  1450. plugin->address_update_task = NULL;
  1451. address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
  1452. PLUGIN_NAME,
  1453. ua,
  1454. len,
  1455. GNUNET_HELLO_ADDRESS_INFO_NONE);
  1456. plugin->env->notify_address (plugin->env->cls, GNUNET_YES, address);
  1457. GNUNET_free (ua);
  1458. GNUNET_free (address);
  1459. }
  1460. /**
  1461. * Function called on sessions to disconnect
  1462. *
  1463. * @param cls the plugin
  1464. * @param key peer identity (unused)
  1465. * @param value the `struct GNUNET_ATS_Session *` to disconnect
  1466. * @return #GNUNET_YES (always, continue to iterate)
  1467. */
  1468. static int
  1469. get_session_delete_it (void *cls,
  1470. const struct GNUNET_PeerIdentity *key,
  1471. void *value)
  1472. {
  1473. struct Plugin *plugin = cls;
  1474. struct GNUNET_ATS_Session *session = value;
  1475. unix_plugin_session_disconnect (plugin, session);
  1476. return GNUNET_YES;
  1477. }
  1478. /**
  1479. * Disconnect from a remote node. Clean up session if we have one for this peer
  1480. *
  1481. * @param cls closure for this call (should be handle to Plugin)
  1482. * @param target the peeridentity of the peer to disconnect
  1483. * @return #GNUNET_OK on success, #GNUNET_SYSERR if the operation failed
  1484. */
  1485. static void
  1486. unix_plugin_peer_disconnect (void *cls,
  1487. const struct GNUNET_PeerIdentity *target)
  1488. {
  1489. struct Plugin *plugin = cls;
  1490. GNUNET_CONTAINER_multipeermap_get_multiple (plugin->session_map,
  1491. target,
  1492. &get_session_delete_it,
  1493. plugin);
  1494. }
  1495. /**
  1496. * Return information about the given session to the
  1497. * monitor callback.
  1498. *
  1499. * @param cls the `struct Plugin` with the monitor callback (`sic`)
  1500. * @param peer peer we send information about
  1501. * @param value our `struct GNUNET_ATS_Session` to send information about
  1502. * @return #GNUNET_OK (continue to iterate)
  1503. */
  1504. static int
  1505. send_session_info_iter (void *cls,
  1506. const struct GNUNET_PeerIdentity *peer,
  1507. void *value)
  1508. {
  1509. struct Plugin *plugin = cls;
  1510. struct GNUNET_ATS_Session *session = value;
  1511. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_INIT);
  1512. notify_session_monitor (plugin, session, GNUNET_TRANSPORT_SS_UP);
  1513. return GNUNET_OK;
  1514. }
  1515. /**
  1516. * Begin monitoring sessions of a plugin. There can only
  1517. * be one active monitor per plugin (i.e. if there are
  1518. * multiple monitors, the transport service needs to
  1519. * multiplex the generated events over all of them).
  1520. *
  1521. * @param cls closure of the plugin
  1522. * @param sic callback to invoke, NULL to disable monitor;
  1523. * plugin will being by iterating over all active
  1524. * sessions immediately and then enter monitor mode
  1525. * @param sic_cls closure for @a sic
  1526. */
  1527. static void
  1528. unix_plugin_setup_monitor (void *cls,
  1529. GNUNET_TRANSPORT_SessionInfoCallback sic,
  1530. void *sic_cls)
  1531. {
  1532. struct Plugin *plugin = cls;
  1533. plugin->sic = sic;
  1534. plugin->sic_cls = sic_cls;
  1535. if (NULL != sic)
  1536. {
  1537. GNUNET_CONTAINER_multipeermap_iterate (plugin->session_map,
  1538. &send_session_info_iter,
  1539. plugin);
  1540. /* signal end of first iteration */
  1541. sic (sic_cls, NULL, NULL);
  1542. }
  1543. }
  1544. /**
  1545. * The exported method. Initializes the plugin and returns a
  1546. * struct with the callbacks.
  1547. *
  1548. * @param cls the plugin's execution environment
  1549. * @return NULL on error, plugin functions otherwise
  1550. */
  1551. void *
  1552. libgnunet_plugin_transport_unix_init (void *cls)
  1553. {
  1554. struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
  1555. struct GNUNET_TRANSPORT_PluginFunctions *api;
  1556. struct Plugin *plugin;
  1557. int sockets_created;
  1558. if (NULL == env->receive)
  1559. {
  1560. /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
  1561. initialze the plugin or the API */
  1562. api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
  1563. api->cls = NULL;
  1564. api->address_pretty_printer = &unix_plugin_address_pretty_printer;
  1565. api->address_to_string = &unix_plugin_address_to_string;
  1566. api->string_to_address = &unix_plugin_string_to_address;
  1567. return api;
  1568. }
  1569. plugin = GNUNET_new (struct Plugin);
  1570. if (GNUNET_OK !=
  1571. GNUNET_CONFIGURATION_get_value_filename (env->cfg,
  1572. "transport-unix",
  1573. "UNIXPATH",
  1574. &plugin->unix_socket_path))
  1575. {
  1576. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
  1577. "transport-unix",
  1578. "UNIXPATH");
  1579. GNUNET_free (plugin);
  1580. return NULL;
  1581. }
  1582. plugin->env = env;
  1583. /* Initialize my flags */
  1584. #ifdef __linux__
  1585. plugin->is_abstract =
  1586. GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
  1587. "testing",
  1588. "USE_ABSTRACT_SOCKETS");
  1589. #endif
  1590. plugin->myoptions = UNIX_OPTIONS_NONE;
  1591. if (GNUNET_YES == plugin->is_abstract)
  1592. plugin->myoptions = UNIX_OPTIONS_USE_ABSTRACT_SOCKETS;
  1593. api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
  1594. api->cls = plugin;
  1595. api->get_session = &unix_plugin_get_session;
  1596. api->send = &unix_plugin_send;
  1597. api->disconnect_peer = &unix_plugin_peer_disconnect;
  1598. api->disconnect_session = &unix_plugin_session_disconnect;
  1599. api->query_keepalive_factor = &unix_plugin_query_keepalive_factor;
  1600. api->address_pretty_printer = &unix_plugin_address_pretty_printer;
  1601. api->address_to_string = &unix_plugin_address_to_string;
  1602. api->check_address = &unix_plugin_check_address;
  1603. api->string_to_address = &unix_plugin_string_to_address;
  1604. api->get_network = &unix_plugin_get_network;
  1605. api->get_network_for_address = &unix_plugin_get_network_for_address;
  1606. api->update_session_timeout = &unix_plugin_update_session_timeout;
  1607. api->setup_monitor = &unix_plugin_setup_monitor;
  1608. sockets_created = unix_transport_server_start (plugin);
  1609. if ((0 == sockets_created) || (GNUNET_SYSERR == sockets_created))
  1610. {
  1611. LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to open UNIX listen socket\n"));
  1612. GNUNET_free (api);
  1613. GNUNET_free (plugin->unix_socket_path);
  1614. GNUNET_free (plugin);
  1615. return NULL;
  1616. }
  1617. plugin->session_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
  1618. plugin->address_update_task =
  1619. GNUNET_SCHEDULER_add_now (&address_notification, plugin);
  1620. return api;
  1621. }
  1622. /**
  1623. * Shutdown the plugin.
  1624. *
  1625. * @param cls the plugin API returned from the initialization function
  1626. * @return NULL (always)
  1627. */
  1628. void *
  1629. libgnunet_plugin_transport_unix_done (void *cls)
  1630. {
  1631. struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
  1632. struct Plugin *plugin = api->cls;
  1633. struct GNUNET_HELLO_Address *address;
  1634. struct UNIXMessageWrapper *msgw;
  1635. struct UnixAddress *ua;
  1636. size_t len;
  1637. struct GNUNET_ATS_Session *session;
  1638. if (NULL == plugin)
  1639. {
  1640. GNUNET_free (api);
  1641. return NULL;
  1642. }
  1643. len = sizeof(struct UnixAddress) + strlen (plugin->unix_socket_path) + 1;
  1644. ua = GNUNET_malloc (len);
  1645. ua->options = htonl (plugin->myoptions);
  1646. ua->addrlen = htonl (strlen (plugin->unix_socket_path) + 1);
  1647. GNUNET_memcpy (&ua[1],
  1648. plugin->unix_socket_path,
  1649. strlen (plugin->unix_socket_path) + 1);
  1650. address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
  1651. PLUGIN_NAME,
  1652. ua,
  1653. len,
  1654. GNUNET_HELLO_ADDRESS_INFO_NONE);
  1655. plugin->env->notify_address (plugin->env->cls, GNUNET_NO, address);
  1656. GNUNET_free (address);
  1657. GNUNET_free (ua);
  1658. while (NULL != (msgw = plugin->msg_head))
  1659. {
  1660. GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
  1661. session = msgw->session;
  1662. session->msgs_in_queue--;
  1663. GNUNET_assert (session->bytes_in_queue >= msgw->msgsize);
  1664. session->bytes_in_queue -= msgw->msgsize;
  1665. GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize);
  1666. plugin->bytes_in_queue -= msgw->msgsize;
  1667. if (NULL != msgw->cont)
  1668. msgw->cont (msgw->cont_cls,
  1669. &msgw->session->target,
  1670. GNUNET_SYSERR,
  1671. msgw->payload,
  1672. 0);
  1673. GNUNET_free (msgw->msg);
  1674. GNUNET_free (msgw);
  1675. }
  1676. if (NULL != plugin->read_task)
  1677. {
  1678. GNUNET_SCHEDULER_cancel (plugin->read_task);
  1679. plugin->read_task = NULL;
  1680. }
  1681. if (NULL != plugin->write_task)
  1682. {
  1683. GNUNET_SCHEDULER_cancel (plugin->write_task);
  1684. plugin->write_task = NULL;
  1685. }
  1686. if (NULL != plugin->address_update_task)
  1687. {
  1688. GNUNET_SCHEDULER_cancel (plugin->address_update_task);
  1689. plugin->address_update_task = NULL;
  1690. }
  1691. if (NULL != plugin->unix_sock.desc)
  1692. {
  1693. GNUNET_break (GNUNET_OK ==
  1694. GNUNET_NETWORK_socket_close (plugin->unix_sock.desc));
  1695. plugin->unix_sock.desc = NULL;
  1696. }
  1697. GNUNET_CONTAINER_multipeermap_iterate (plugin->session_map,
  1698. &get_session_delete_it,
  1699. plugin);
  1700. GNUNET_CONTAINER_multipeermap_destroy (plugin->session_map);
  1701. GNUNET_break (0 == plugin->bytes_in_queue);
  1702. GNUNET_free (plugin->unix_socket_path);
  1703. GNUNET_free (plugin);
  1704. GNUNET_free (api);
  1705. return NULL;
  1706. }
  1707. /* end of plugin_transport_unix.c */