core_api.c 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2009, 2010 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. 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. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file core/core_api.c
  19. * @brief core service; this is the main API for encrypted P2P
  20. * communications
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_constants.h"
  25. #include "gnunet_core_service.h"
  26. #include "core.h"
  27. /**
  28. * Information we track for each peer.
  29. */
  30. struct PeerRecord
  31. {
  32. /**
  33. * We generally do NOT keep peer records in a DLL; this
  34. * DLL is only used IF this peer's 'pending_head' message
  35. * is ready for transmission.
  36. */
  37. struct PeerRecord *prev;
  38. /**
  39. * We generally do NOT keep peer records in a DLL; this
  40. * DLL is only used IF this peer's 'pending_head' message
  41. * is ready for transmission.
  42. */
  43. struct PeerRecord *next;
  44. /**
  45. * Peer the record is about.
  46. */
  47. struct GNUNET_PeerIdentity peer;
  48. /**
  49. * Corresponding core handle.
  50. */
  51. struct GNUNET_CORE_Handle *ch;
  52. /**
  53. * Head of doubly-linked list of pending requests.
  54. * Requests are sorted by deadline *except* for HEAD,
  55. * which is only modified upon transmission to core.
  56. */
  57. struct GNUNET_CORE_TransmitHandle *pending_head;
  58. /**
  59. * Tail of doubly-linked list of pending requests.
  60. */
  61. struct GNUNET_CORE_TransmitHandle *pending_tail;
  62. /**
  63. * Pending callback waiting for peer information, or NULL for none.
  64. */
  65. GNUNET_CORE_PeerConfigurationInfoCallback pcic;
  66. /**
  67. * Closure for pcic.
  68. */
  69. void *pcic_cls;
  70. /**
  71. * Pointer to free when we call pcic and to use to cancel
  72. * preference change on disconnect.
  73. */
  74. struct GNUNET_CORE_InformationRequestContext *pcic_ptr;
  75. /**
  76. * Request information ID for the given pcic (needed in case a
  77. * request is cancelled after being submitted to core and a new
  78. * one is generated; in this case, we need to avoid matching the
  79. * reply to the first (cancelled) request to the second request).
  80. */
  81. uint32_t rim_id;
  82. /**
  83. * ID of timeout task for the 'pending_head' handle
  84. * which is the one with the smallest timeout.
  85. */
  86. GNUNET_SCHEDULER_TaskIdentifier timeout_task;
  87. /**
  88. * ID of task to run 'next_request_transmission'.
  89. */
  90. GNUNET_SCHEDULER_TaskIdentifier ntr_task;
  91. /**
  92. * Current size of the queue of pending requests.
  93. */
  94. unsigned int queue_size;
  95. /**
  96. * SendMessageRequest ID generator for this peer.
  97. */
  98. uint16_t smr_id_gen;
  99. };
  100. /**
  101. * Entry in a doubly-linked list of control messages to be transmitted
  102. * to the core service. Control messages include traffic allocation,
  103. * connection requests and of course our initial 'init' request.
  104. *
  105. * The actual message is allocated at the end of this struct.
  106. */
  107. struct ControlMessage
  108. {
  109. /**
  110. * This is a doubly-linked list.
  111. */
  112. struct ControlMessage *next;
  113. /**
  114. * This is a doubly-linked list.
  115. */
  116. struct ControlMessage *prev;
  117. /**
  118. * Function to run after transmission failed/succeeded.
  119. */
  120. GNUNET_CORE_ControlContinuation cont;
  121. /**
  122. * Closure for 'cont'.
  123. */
  124. void *cont_cls;
  125. /**
  126. * Transmit handle (if one is associated with this ControlMessage), or NULL.
  127. */
  128. struct GNUNET_CORE_TransmitHandle *th;
  129. };
  130. /**
  131. * Context for the core service connection.
  132. */
  133. struct GNUNET_CORE_Handle
  134. {
  135. /**
  136. * Configuration we're using.
  137. */
  138. const struct GNUNET_CONFIGURATION_Handle *cfg;
  139. /**
  140. * Closure for the various callbacks.
  141. */
  142. void *cls;
  143. /**
  144. * Function to call once we've handshaked with the core service.
  145. */
  146. GNUNET_CORE_StartupCallback init;
  147. /**
  148. * Function to call whenever we're notified about a peer connecting.
  149. */
  150. GNUNET_CORE_ConnectEventHandler connects;
  151. /**
  152. * Function to call whenever we're notified about a peer disconnecting.
  153. */
  154. GNUNET_CORE_DisconnectEventHandler disconnects;
  155. /**
  156. * Function to call whenever we're notified about a peer changing status.
  157. */
  158. GNUNET_CORE_PeerStatusEventHandler status_events;
  159. /**
  160. * Function to call whenever we receive an inbound message.
  161. */
  162. GNUNET_CORE_MessageCallback inbound_notify;
  163. /**
  164. * Function to call whenever we receive an outbound message.
  165. */
  166. GNUNET_CORE_MessageCallback outbound_notify;
  167. /**
  168. * Function handlers for messages of particular type.
  169. */
  170. const struct GNUNET_CORE_MessageHandler *handlers;
  171. /**
  172. * Our connection to the service.
  173. */
  174. struct GNUNET_CLIENT_Connection *client;
  175. /**
  176. * Handle for our current transmission request.
  177. */
  178. struct GNUNET_CLIENT_TransmitHandle *cth;
  179. /**
  180. * Head of doubly-linked list of pending requests.
  181. */
  182. struct ControlMessage *control_pending_head;
  183. /**
  184. * Tail of doubly-linked list of pending requests.
  185. */
  186. struct ControlMessage *control_pending_tail;
  187. /**
  188. * Head of doubly-linked list of peers that are core-approved
  189. * to send their next message.
  190. */
  191. struct PeerRecord *ready_peer_head;
  192. /**
  193. * Tail of doubly-linked list of peers that are core-approved
  194. * to send their next message.
  195. */
  196. struct PeerRecord *ready_peer_tail;
  197. /**
  198. * Hash map listing all of the peers that we are currently
  199. * connected to.
  200. */
  201. struct GNUNET_CONTAINER_MultiHashMap *peers;
  202. /**
  203. * Identity of this peer.
  204. */
  205. struct GNUNET_PeerIdentity me;
  206. /**
  207. * ID of reconnect task (if any).
  208. */
  209. GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
  210. /**
  211. * Current delay we use for re-trying to connect to core.
  212. */
  213. struct GNUNET_TIME_Relative retry_backoff;
  214. /**
  215. * Request information ID generator.
  216. */
  217. uint32_t rim_id_gen;
  218. /**
  219. * Number of messages we are allowed to queue per target.
  220. */
  221. unsigned int queue_size;
  222. /**
  223. * Number of entries in the handlers array.
  224. */
  225. unsigned int hcnt;
  226. /**
  227. * For inbound notifications without a specific handler, do
  228. * we expect to only receive headers?
  229. */
  230. int inbound_hdr_only;
  231. /**
  232. * For outbound notifications without a specific handler, do
  233. * we expect to only receive headers?
  234. */
  235. int outbound_hdr_only;
  236. /**
  237. * Are we currently disconnected and hence unable to forward
  238. * requests?
  239. */
  240. int currently_down;
  241. };
  242. /**
  243. * Handle for a transmission request.
  244. */
  245. struct GNUNET_CORE_TransmitHandle
  246. {
  247. /**
  248. * We keep active transmit handles in a doubly-linked list.
  249. */
  250. struct GNUNET_CORE_TransmitHandle *next;
  251. /**
  252. * We keep active transmit handles in a doubly-linked list.
  253. */
  254. struct GNUNET_CORE_TransmitHandle *prev;
  255. /**
  256. * Corresponding peer record.
  257. */
  258. struct PeerRecord *peer;
  259. /**
  260. * Corresponding SEND_REQUEST message. Only non-NULL
  261. * while SEND_REQUEST message is pending.
  262. */
  263. struct ControlMessage *cm;
  264. /**
  265. * Function that will be called to get the actual request
  266. * (once we are ready to transmit this request to the core).
  267. * The function will be called with a NULL buffer to signal
  268. * timeout.
  269. */
  270. GNUNET_CONNECTION_TransmitReadyNotify get_message;
  271. /**
  272. * Closure for get_message.
  273. */
  274. void *get_message_cls;
  275. /**
  276. * Timeout for this handle.
  277. */
  278. struct GNUNET_TIME_Absolute timeout;
  279. /**
  280. * How important is this message?
  281. */
  282. uint32_t priority;
  283. /**
  284. * Size of this request.
  285. */
  286. uint16_t msize;
  287. /**
  288. * Send message request ID for this request.
  289. */
  290. uint16_t smr_id;
  291. /**
  292. * Is corking allowed?
  293. */
  294. int cork;
  295. };
  296. /**
  297. * Our current client connection went down. Clean it up
  298. * and try to reconnect!
  299. *
  300. * @param h our handle to the core service
  301. */
  302. static void
  303. reconnect (struct GNUNET_CORE_Handle *h);
  304. /**
  305. * Task schedule to try to re-connect to core.
  306. *
  307. * @param cls the 'struct GNUNET_CORE_Handle'
  308. * @param tc task context
  309. */
  310. static void
  311. reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  312. {
  313. struct GNUNET_CORE_Handle *h = cls;
  314. h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
  315. #if DEBUG_CORE
  316. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  317. "Connecting to CORE service after delay\n");
  318. #endif
  319. reconnect (h);
  320. }
  321. /**
  322. * Notify clients about disconnect and free
  323. * the entry for connected peer.
  324. *
  325. * @param cls the 'struct GNUNET_CORE_Handle*'
  326. * @param key the peer identity (not used)
  327. * @param value the 'struct PeerRecord' to free.
  328. * @return GNUNET_YES (continue)
  329. */
  330. static int
  331. disconnect_and_free_peer_entry (void *cls, const GNUNET_HashCode * key,
  332. void *value)
  333. {
  334. static struct GNUNET_BANDWIDTH_Value32NBO zero;
  335. struct GNUNET_CORE_Handle *h = cls;
  336. struct GNUNET_CORE_TransmitHandle *th;
  337. struct PeerRecord *pr = value;
  338. GNUNET_CORE_PeerConfigurationInfoCallback pcic;
  339. void *pcic_cls;
  340. if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK)
  341. {
  342. GNUNET_SCHEDULER_cancel (pr->timeout_task);
  343. pr->timeout_task = GNUNET_SCHEDULER_NO_TASK;
  344. }
  345. if (pr->ntr_task != GNUNET_SCHEDULER_NO_TASK)
  346. {
  347. GNUNET_SCHEDULER_cancel (pr->ntr_task);
  348. pr->ntr_task = GNUNET_SCHEDULER_NO_TASK;
  349. }
  350. if ((pr->prev != NULL) || (pr->next != NULL) || (h->ready_peer_head == pr))
  351. GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr);
  352. if (h->disconnects != NULL)
  353. h->disconnects (h->cls, &pr->peer);
  354. /* all requests should have been cancelled, clean up anyway, just in case */
  355. GNUNET_break (pr->queue_size == 0);
  356. if (NULL != (pcic = pr->pcic))
  357. {
  358. GNUNET_break (0);
  359. pcic_cls = pr->pcic_cls;
  360. GNUNET_CORE_peer_change_preference_cancel (pr->pcic_ptr);
  361. pcic (pcic_cls, &pr->peer, zero, 0, GNUNET_TIME_UNIT_FOREVER_REL, 0);
  362. }
  363. while (NULL != (th = pr->pending_head))
  364. {
  365. GNUNET_break (0);
  366. GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th);
  367. pr->queue_size--;
  368. if (th->cm != NULL)
  369. th->cm->th = NULL;
  370. GNUNET_free (th);
  371. }
  372. /* done with 'voluntary' cleanups, now on to normal freeing */
  373. GNUNET_assert (GNUNET_YES ==
  374. GNUNET_CONTAINER_multihashmap_remove (h->peers, key, pr));
  375. GNUNET_assert (pr->pending_head == NULL);
  376. GNUNET_assert (pr->pending_tail == NULL);
  377. GNUNET_assert (pr->ch = h);
  378. GNUNET_assert (pr->queue_size == 0);
  379. GNUNET_assert (pr->timeout_task == GNUNET_SCHEDULER_NO_TASK);
  380. GNUNET_assert (pr->ntr_task == GNUNET_SCHEDULER_NO_TASK);
  381. GNUNET_free (pr);
  382. return GNUNET_YES;
  383. }
  384. /**
  385. * Close down any existing connection to the CORE service and
  386. * try re-establishing it later.
  387. *
  388. * @param h our handle
  389. */
  390. static void
  391. reconnect_later (struct GNUNET_CORE_Handle *h)
  392. {
  393. struct ControlMessage *cm;
  394. struct PeerRecord *pr;
  395. GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
  396. if (NULL != h->cth)
  397. {
  398. GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth);
  399. h->cth = NULL;
  400. }
  401. if (h->client != NULL)
  402. {
  403. GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
  404. h->client = NULL;
  405. }
  406. h->currently_down = GNUNET_YES;
  407. GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
  408. h->reconnect_task =
  409. GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_task, h);
  410. while (NULL != (cm = h->control_pending_head))
  411. {
  412. GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
  413. h->control_pending_tail, cm);
  414. if (cm->th != NULL)
  415. cm->th->cm = NULL;
  416. if (cm->cont != NULL)
  417. cm->cont (cm->cont_cls, GNUNET_NO);
  418. GNUNET_free (cm);
  419. }
  420. GNUNET_CONTAINER_multihashmap_iterate (h->peers,
  421. &disconnect_and_free_peer_entry, h);
  422. while (NULL != (pr = h->ready_peer_head))
  423. GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr);
  424. GNUNET_assert (h->control_pending_head == NULL);
  425. h->retry_backoff =
  426. GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, h->retry_backoff);
  427. h->retry_backoff = GNUNET_TIME_relative_multiply (h->retry_backoff, 2);
  428. }
  429. /**
  430. * Check the list of pending requests, send the next
  431. * one to the core.
  432. *
  433. * @param h core handle
  434. * @param ignore_currently_down transmit message even if not initialized?
  435. */
  436. static void
  437. trigger_next_request (struct GNUNET_CORE_Handle *h, int ignore_currently_down);
  438. /**
  439. * The given request hit its timeout. Remove from the
  440. * doubly-linked list and call the respective continuation.
  441. *
  442. * @param cls the transmit handle of the request that timed out
  443. * @param tc context, can be NULL (!)
  444. */
  445. static void
  446. transmission_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
  447. /**
  448. * Send a control message to the peer asking for transmission
  449. * of the message in the given peer record.
  450. *
  451. * @param pr peer to request transmission to
  452. */
  453. static void
  454. request_next_transmission (struct PeerRecord *pr)
  455. {
  456. struct GNUNET_CORE_Handle *h = pr->ch;
  457. struct ControlMessage *cm;
  458. struct SendMessageRequest *smr;
  459. struct GNUNET_CORE_TransmitHandle *th;
  460. if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK)
  461. {
  462. GNUNET_SCHEDULER_cancel (pr->timeout_task);
  463. pr->timeout_task = GNUNET_SCHEDULER_NO_TASK;
  464. }
  465. if (NULL == (th = pr->pending_head))
  466. {
  467. trigger_next_request (h, GNUNET_NO);
  468. return;
  469. }
  470. if (th->cm != NULL)
  471. return; /* already done */
  472. GNUNET_assert (pr->prev == NULL);
  473. GNUNET_assert (pr->next == NULL);
  474. pr->timeout_task =
  475. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
  476. (th->timeout), &transmission_timeout, pr);
  477. cm = GNUNET_malloc (sizeof (struct ControlMessage) +
  478. sizeof (struct SendMessageRequest));
  479. th->cm = cm;
  480. cm->th = th;
  481. smr = (struct SendMessageRequest *) &cm[1];
  482. smr->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
  483. smr->header.size = htons (sizeof (struct SendMessageRequest));
  484. smr->priority = htonl (th->priority);
  485. smr->deadline = GNUNET_TIME_absolute_hton (th->timeout);
  486. smr->peer = pr->peer;
  487. smr->queue_size = htonl (pr->queue_size);
  488. smr->size = htons (th->msize);
  489. smr->smr_id = htons (th->smr_id = pr->smr_id_gen++);
  490. GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
  491. h->control_pending_tail, cm);
  492. #if DEBUG_CORE
  493. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  494. "Adding SEND REQUEST for peer `%s' to message queue\n",
  495. GNUNET_i2s (&pr->peer));
  496. #endif
  497. trigger_next_request (h, GNUNET_NO);
  498. }
  499. /**
  500. * The given request hit its timeout. Remove from the
  501. * doubly-linked list and call the respective continuation.
  502. *
  503. * @param cls the transmit handle of the request that timed out
  504. * @param tc context, can be NULL (!)
  505. */
  506. static void
  507. transmission_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  508. {
  509. struct PeerRecord *pr = cls;
  510. struct GNUNET_CORE_Handle *h = pr->ch;
  511. struct GNUNET_CORE_TransmitHandle *th;
  512. pr->timeout_task = GNUNET_SCHEDULER_NO_TASK;
  513. th = pr->pending_head;
  514. GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th);
  515. pr->queue_size--;
  516. if ((pr->prev != NULL) || (pr->next != NULL) || (pr == h->ready_peer_head))
  517. {
  518. /* the request that was 'approved' by core was
  519. * canceled before it could be transmitted; remove
  520. * us from the 'ready' list */
  521. GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr);
  522. }
  523. #if DEBUG_CORE
  524. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  525. "Signalling timeout of request for transmission to CORE service\n");
  526. #endif
  527. request_next_transmission (pr);
  528. GNUNET_assert (0 == th->get_message (th->get_message_cls, 0, NULL));
  529. GNUNET_free (th);
  530. }
  531. /**
  532. * Transmit the next message to the core service.
  533. */
  534. static size_t
  535. transmit_message (void *cls, size_t size, void *buf)
  536. {
  537. struct GNUNET_CORE_Handle *h = cls;
  538. struct ControlMessage *cm;
  539. struct GNUNET_CORE_TransmitHandle *th;
  540. struct PeerRecord *pr;
  541. struct SendMessage *sm;
  542. const struct GNUNET_MessageHeader *hdr;
  543. uint16_t msize;
  544. size_t ret;
  545. GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
  546. h->cth = NULL;
  547. if (buf == NULL)
  548. {
  549. #if DEBUG_CORE
  550. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  551. "Transmission failed, initiating reconnect\n");
  552. #endif
  553. reconnect_later (h);
  554. return 0;
  555. }
  556. /* first check for control messages */
  557. if (NULL != (cm = h->control_pending_head))
  558. {
  559. hdr = (const struct GNUNET_MessageHeader *) &cm[1];
  560. msize = ntohs (hdr->size);
  561. if (size < msize)
  562. {
  563. trigger_next_request (h, GNUNET_NO);
  564. return 0;
  565. }
  566. #if DEBUG_CORE
  567. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  568. "Transmitting control message with %u bytes of type %u to core.\n",
  569. (unsigned int) msize, (unsigned int) ntohs (hdr->type));
  570. #endif
  571. memcpy (buf, hdr, msize);
  572. GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
  573. h->control_pending_tail, cm);
  574. if (cm->th != NULL)
  575. cm->th->cm = NULL;
  576. if (NULL != cm->cont)
  577. cm->cont (cm->cont_cls, GNUNET_OK);
  578. GNUNET_free (cm);
  579. trigger_next_request (h, GNUNET_NO);
  580. return msize;
  581. }
  582. /* now check for 'ready' P2P messages */
  583. if (NULL != (pr = h->ready_peer_head))
  584. {
  585. GNUNET_assert (pr->pending_head != NULL);
  586. th = pr->pending_head;
  587. if (size < th->msize + sizeof (struct SendMessage))
  588. {
  589. trigger_next_request (h, GNUNET_NO);
  590. return 0;
  591. }
  592. GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr);
  593. GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th);
  594. pr->queue_size--;
  595. if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK)
  596. {
  597. GNUNET_SCHEDULER_cancel (pr->timeout_task);
  598. pr->timeout_task = GNUNET_SCHEDULER_NO_TASK;
  599. }
  600. #if DEBUG_CORE
  601. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  602. "Transmitting SEND request to `%s' with %u bytes.\n",
  603. GNUNET_i2s (&pr->peer), (unsigned int) th->msize);
  604. #endif
  605. sm = (struct SendMessage *) buf;
  606. sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND);
  607. sm->priority = htonl (th->priority);
  608. sm->deadline = GNUNET_TIME_absolute_hton (th->timeout);
  609. sm->peer = pr->peer;
  610. sm->cork = htonl ((uint32_t) th->cork);
  611. sm->reserved = htonl (0);
  612. ret =
  613. th->get_message (th->get_message_cls,
  614. size - sizeof (struct SendMessage), &sm[1]);
  615. #if DEBUG_CORE
  616. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  617. "Transmitting SEND request to `%s' yielded %u bytes.\n",
  618. GNUNET_i2s (&pr->peer), ret);
  619. #endif
  620. GNUNET_free (th);
  621. if (0 == ret)
  622. {
  623. #if DEBUG_CORE
  624. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  625. "Size of clients message to peer %s is 0!\n",
  626. GNUNET_i2s (&pr->peer));
  627. #endif
  628. /* client decided to send nothing! */
  629. request_next_transmission (pr);
  630. return 0;
  631. }
  632. #if DEBUG_CORE
  633. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  634. "Produced SEND message to core with %u bytes payload\n",
  635. (unsigned int) ret);
  636. #endif
  637. GNUNET_assert (ret >= sizeof (struct GNUNET_MessageHeader));
  638. if (ret + sizeof (struct SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
  639. {
  640. GNUNET_break (0);
  641. request_next_transmission (pr);
  642. return 0;
  643. }
  644. ret += sizeof (struct SendMessage);
  645. sm->header.size = htons (ret);
  646. GNUNET_assert (ret <= size);
  647. request_next_transmission (pr);
  648. return ret;
  649. }
  650. return 0;
  651. }
  652. /**
  653. * Check the list of pending requests, send the next
  654. * one to the core.
  655. *
  656. * @param h core handle
  657. * @param ignore_currently_down transmit message even if not initialized?
  658. */
  659. static void
  660. trigger_next_request (struct GNUNET_CORE_Handle *h, int ignore_currently_down)
  661. {
  662. uint16_t msize;
  663. if ((GNUNET_YES == h->currently_down) && (ignore_currently_down == GNUNET_NO))
  664. {
  665. #if DEBUG_CORE
  666. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  667. "Core connection down, not processing queue\n");
  668. #endif
  669. return;
  670. }
  671. if (NULL != h->cth)
  672. {
  673. #if DEBUG_CORE
  674. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  675. "Request pending, not processing queue\n");
  676. #endif
  677. return;
  678. }
  679. if (h->control_pending_head != NULL)
  680. msize =
  681. ntohs (((struct GNUNET_MessageHeader *) &h->
  682. control_pending_head[1])->size);
  683. else if (h->ready_peer_head != NULL)
  684. msize =
  685. h->ready_peer_head->pending_head->msize + sizeof (struct SendMessage);
  686. else
  687. {
  688. #if DEBUG_CORE
  689. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  690. "Request queue empty, not processing queue\n");
  691. #endif
  692. return; /* no pending message */
  693. }
  694. h->cth =
  695. GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
  696. GNUNET_TIME_UNIT_FOREVER_REL,
  697. GNUNET_NO, &transmit_message, h);
  698. }
  699. /**
  700. * Handler for notification messages received from the core.
  701. *
  702. * @param cls our "struct GNUNET_CORE_Handle"
  703. * @param msg the message received from the core service
  704. */
  705. static void
  706. main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg)
  707. {
  708. struct GNUNET_CORE_Handle *h = cls;
  709. const struct InitReplyMessage *m;
  710. const struct ConnectNotifyMessage *cnm;
  711. const struct DisconnectNotifyMessage *dnm;
  712. const struct NotifyTrafficMessage *ntm;
  713. const struct GNUNET_MessageHeader *em;
  714. const struct ConfigurationInfoMessage *cim;
  715. const struct PeerStatusNotifyMessage *psnm;
  716. const struct SendMessageReady *smr;
  717. const struct GNUNET_CORE_MessageHandler *mh;
  718. GNUNET_CORE_StartupCallback init;
  719. GNUNET_CORE_PeerConfigurationInfoCallback pcic;
  720. struct PeerRecord *pr;
  721. struct GNUNET_CORE_TransmitHandle *th;
  722. unsigned int hpos;
  723. int trigger;
  724. uint16_t msize;
  725. uint16_t et;
  726. uint32_t ats_count;
  727. if (msg == NULL)
  728. {
  729. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  730. _
  731. ("Client was disconnected from core service, trying to reconnect.\n"));
  732. reconnect_later (h);
  733. return;
  734. }
  735. msize = ntohs (msg->size);
  736. #if DEBUG_CORE > 2
  737. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  738. "Processing message of type %u and size %u from core service\n",
  739. ntohs (msg->type), msize);
  740. #endif
  741. switch (ntohs (msg->type))
  742. {
  743. case GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY:
  744. if (ntohs (msg->size) != sizeof (struct InitReplyMessage))
  745. {
  746. GNUNET_break (0);
  747. reconnect_later (h);
  748. return;
  749. }
  750. m = (const struct InitReplyMessage *) msg;
  751. GNUNET_break (0 == ntohl (m->reserved));
  752. /* start our message processing loop */
  753. if (GNUNET_YES == h->currently_down)
  754. {
  755. h->currently_down = GNUNET_NO;
  756. trigger_next_request (h, GNUNET_NO);
  757. }
  758. h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
  759. GNUNET_CRYPTO_hash (&m->publicKey,
  760. sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
  761. &h->me.hashPubKey);
  762. if (NULL != (init = h->init))
  763. {
  764. /* mark so we don't call init on reconnect */
  765. h->init = NULL;
  766. #if DEBUG_CORE
  767. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  768. "Connected to core service of peer `%s'.\n",
  769. GNUNET_i2s (&h->me));
  770. #endif
  771. init (h->cls, h, &h->me, &m->publicKey);
  772. }
  773. else
  774. {
  775. #if DEBUG_CORE
  776. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  777. "Successfully reconnected to core service.\n");
  778. #endif
  779. }
  780. /* fake 'connect to self' */
  781. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &h->me.hashPubKey);
  782. GNUNET_assert (pr == NULL);
  783. pr = GNUNET_malloc (sizeof (struct PeerRecord));
  784. pr->peer = h->me;
  785. pr->ch = h;
  786. GNUNET_assert (GNUNET_YES ==
  787. GNUNET_CONTAINER_multihashmap_put (h->peers,
  788. &h->me.hashPubKey, pr,
  789. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
  790. if (NULL != h->connects)
  791. h->connects (h->cls, &h->me, NULL);
  792. break;
  793. case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT:
  794. if (msize < sizeof (struct ConnectNotifyMessage))
  795. {
  796. GNUNET_break (0);
  797. reconnect_later (h);
  798. return;
  799. }
  800. cnm = (const struct ConnectNotifyMessage *) msg;
  801. ats_count = ntohl (cnm->ats_count);
  802. if ((msize !=
  803. sizeof (struct ConnectNotifyMessage) +
  804. ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)) ||
  805. (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR !=
  806. ntohl ((&cnm->ats)[ats_count].type)))
  807. {
  808. GNUNET_break (0);
  809. reconnect_later (h);
  810. return;
  811. }
  812. #if DEBUG_CORE
  813. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  814. "Received notification about connection from `%s'.\n",
  815. GNUNET_i2s (&cnm->peer));
  816. #endif
  817. if (0 == memcmp (&h->me, &cnm->peer, sizeof (struct GNUNET_PeerIdentity)))
  818. {
  819. /* connect to self!? */
  820. GNUNET_break (0);
  821. return;
  822. }
  823. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &cnm->peer.hashPubKey);
  824. if (pr != NULL)
  825. {
  826. GNUNET_break (0);
  827. reconnect_later (h);
  828. return;
  829. }
  830. pr = GNUNET_malloc (sizeof (struct PeerRecord));
  831. pr->peer = cnm->peer;
  832. pr->ch = h;
  833. GNUNET_assert (GNUNET_YES ==
  834. GNUNET_CONTAINER_multihashmap_put (h->peers,
  835. &cnm->peer.hashPubKey, pr,
  836. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
  837. if (NULL != h->connects)
  838. h->connects (h->cls, &cnm->peer, &cnm->ats);
  839. break;
  840. case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT:
  841. if (msize != sizeof (struct DisconnectNotifyMessage))
  842. {
  843. GNUNET_break (0);
  844. reconnect_later (h);
  845. return;
  846. }
  847. dnm = (const struct DisconnectNotifyMessage *) msg;
  848. if (0 == memcmp (&h->me, &dnm->peer, sizeof (struct GNUNET_PeerIdentity)))
  849. {
  850. /* connection to self!? */
  851. GNUNET_break (0);
  852. return;
  853. }
  854. GNUNET_break (0 == ntohl (dnm->reserved));
  855. #if DEBUG_CORE
  856. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  857. "Received notification about disconnect from `%s'.\n",
  858. GNUNET_i2s (&dnm->peer));
  859. #endif
  860. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &dnm->peer.hashPubKey);
  861. if (pr == NULL)
  862. {
  863. GNUNET_break (0);
  864. reconnect_later (h);
  865. return;
  866. }
  867. trigger = ((pr->prev != NULL) || (pr->next != NULL) ||
  868. (h->ready_peer_head == pr));
  869. disconnect_and_free_peer_entry (h, &dnm->peer.hashPubKey, pr);
  870. if (trigger)
  871. trigger_next_request (h, GNUNET_NO);
  872. break;
  873. case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE:
  874. if (NULL == h->status_events)
  875. {
  876. GNUNET_break (0);
  877. return;
  878. }
  879. if (msize < sizeof (struct PeerStatusNotifyMessage))
  880. {
  881. GNUNET_break (0);
  882. reconnect_later (h);
  883. return;
  884. }
  885. psnm = (const struct PeerStatusNotifyMessage *) msg;
  886. if (0 == memcmp (&h->me, &psnm->peer, sizeof (struct GNUNET_PeerIdentity)))
  887. {
  888. /* self-change!? */
  889. GNUNET_break (0);
  890. return;
  891. }
  892. ats_count = ntohl (psnm->ats_count);
  893. if ((msize !=
  894. sizeof (struct PeerStatusNotifyMessage) +
  895. ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)) ||
  896. (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR !=
  897. ntohl ((&psnm->ats)[ats_count].type)))
  898. {
  899. GNUNET_break (0);
  900. reconnect_later (h);
  901. return;
  902. }
  903. #if DEBUG_CORE > 1
  904. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  905. "Received notification about status change by `%s'.\n",
  906. GNUNET_i2s (&psnm->peer));
  907. #endif
  908. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &psnm->peer.hashPubKey);
  909. if (pr == NULL)
  910. {
  911. GNUNET_break (0);
  912. reconnect_later (h);
  913. return;
  914. }
  915. h->status_events (h->cls, &psnm->peer, psnm->bandwidth_in,
  916. psnm->bandwidth_out,
  917. GNUNET_TIME_absolute_ntoh (psnm->timeout), &psnm->ats);
  918. break;
  919. case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND:
  920. if (msize < sizeof (struct NotifyTrafficMessage))
  921. {
  922. GNUNET_break (0);
  923. reconnect_later (h);
  924. return;
  925. }
  926. ntm = (const struct NotifyTrafficMessage *) msg;
  927. ats_count = ntohl (ntm->ats_count);
  928. if ((msize <
  929. sizeof (struct NotifyTrafficMessage) +
  930. ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) +
  931. sizeof (struct GNUNET_MessageHeader)) ||
  932. (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR !=
  933. ntohl ((&ntm->ats)[ats_count].type)))
  934. {
  935. GNUNET_break (0);
  936. reconnect_later (h);
  937. return;
  938. }
  939. em = (const struct GNUNET_MessageHeader *) &(&ntm->ats)[ats_count + 1];
  940. #if DEBUG_CORE
  941. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  942. "Received message of type %u and size %u from peer `%4s'\n",
  943. ntohs (em->type), ntohs (em->size), GNUNET_i2s (&ntm->peer));
  944. #endif
  945. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &ntm->peer.hashPubKey);
  946. if (pr == NULL)
  947. {
  948. GNUNET_break (0);
  949. reconnect_later (h);
  950. return;
  951. }
  952. if ((GNUNET_NO == h->inbound_hdr_only) &&
  953. (msize !=
  954. ntohs (em->size) + sizeof (struct NotifyTrafficMessage) +
  955. +ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)))
  956. {
  957. GNUNET_break (0);
  958. reconnect_later (h);
  959. return;
  960. }
  961. et = ntohs (em->type);
  962. for (hpos = 0; hpos < h->hcnt; hpos++)
  963. {
  964. mh = &h->handlers[hpos];
  965. if (mh->type != et)
  966. continue;
  967. if ((mh->expected_size != ntohs (em->size)) && (mh->expected_size != 0))
  968. {
  969. GNUNET_break (0);
  970. continue;
  971. }
  972. if (GNUNET_OK !=
  973. h->handlers[hpos].callback (h->cls, &ntm->peer, em, &ntm->ats))
  974. {
  975. /* error in processing, do not process other messages! */
  976. break;
  977. }
  978. }
  979. if (NULL != h->inbound_notify)
  980. h->inbound_notify (h->cls, &ntm->peer, em, &ntm->ats);
  981. break;
  982. case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND:
  983. if (msize < sizeof (struct NotifyTrafficMessage))
  984. {
  985. GNUNET_break (0);
  986. reconnect_later (h);
  987. return;
  988. }
  989. ntm = (const struct NotifyTrafficMessage *) msg;
  990. if (0 == memcmp (&h->me, &ntm->peer, sizeof (struct GNUNET_PeerIdentity)))
  991. {
  992. /* self-change!? */
  993. GNUNET_break (0);
  994. return;
  995. }
  996. ats_count = ntohl (ntm->ats_count);
  997. if ((msize <
  998. sizeof (struct NotifyTrafficMessage) +
  999. ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) +
  1000. sizeof (struct GNUNET_MessageHeader)) ||
  1001. (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR !=
  1002. ntohl ((&ntm->ats)[ats_count].type)))
  1003. {
  1004. GNUNET_break (0);
  1005. reconnect_later (h);
  1006. return;
  1007. }
  1008. em = (const struct GNUNET_MessageHeader *) &(&ntm->ats)[ats_count + 1];
  1009. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &ntm->peer.hashPubKey);
  1010. if (pr == NULL)
  1011. {
  1012. GNUNET_break (0);
  1013. reconnect_later (h);
  1014. return;
  1015. }
  1016. #if DEBUG_CORE
  1017. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1018. "Received notification about transmission to `%s'.\n",
  1019. GNUNET_i2s (&ntm->peer));
  1020. #endif
  1021. if ((GNUNET_NO == h->outbound_hdr_only) &&
  1022. (msize !=
  1023. ntohs (em->size) + sizeof (struct NotifyTrafficMessage) +
  1024. ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)))
  1025. {
  1026. GNUNET_break (0);
  1027. reconnect_later (h);
  1028. return;
  1029. }
  1030. if (NULL == h->outbound_notify)
  1031. {
  1032. GNUNET_break (0);
  1033. break;
  1034. }
  1035. h->outbound_notify (h->cls, &ntm->peer, em, &ntm->ats);
  1036. break;
  1037. case GNUNET_MESSAGE_TYPE_CORE_SEND_READY:
  1038. if (msize != sizeof (struct SendMessageReady))
  1039. {
  1040. GNUNET_break (0);
  1041. reconnect_later (h);
  1042. return;
  1043. }
  1044. smr = (const struct SendMessageReady *) msg;
  1045. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &smr->peer.hashPubKey);
  1046. if (pr == NULL)
  1047. {
  1048. GNUNET_break (0);
  1049. reconnect_later (h);
  1050. return;
  1051. }
  1052. #if DEBUG_CORE
  1053. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1054. "Received notification about transmission readiness to `%s'.\n",
  1055. GNUNET_i2s (&smr->peer));
  1056. #endif
  1057. if (pr->pending_head == NULL)
  1058. {
  1059. /* request must have been cancelled between the original request
  1060. * and the response from core, ignore core's readiness */
  1061. break;
  1062. }
  1063. th = pr->pending_head;
  1064. if (ntohs (smr->smr_id) != th->smr_id)
  1065. {
  1066. /* READY message is for expired or cancelled message,
  1067. * ignore! (we should have already sent another request) */
  1068. break;
  1069. }
  1070. if ((pr->prev != NULL) || (pr->next != NULL) || (h->ready_peer_head == pr))
  1071. {
  1072. /* we should not already be on the ready list... */
  1073. GNUNET_break (0);
  1074. reconnect_later (h);
  1075. return;
  1076. }
  1077. GNUNET_CONTAINER_DLL_insert (h->ready_peer_head, h->ready_peer_tail, pr);
  1078. trigger_next_request (h, GNUNET_NO);
  1079. break;
  1080. case GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO:
  1081. if (ntohs (msg->size) != sizeof (struct ConfigurationInfoMessage))
  1082. {
  1083. GNUNET_break (0);
  1084. reconnect_later (h);
  1085. return;
  1086. }
  1087. cim = (const struct ConfigurationInfoMessage *) msg;
  1088. if (0 == memcmp (&h->me, &cim->peer, sizeof (struct GNUNET_PeerIdentity)))
  1089. {
  1090. /* self-change!? */
  1091. GNUNET_break (0);
  1092. return;
  1093. }
  1094. #if DEBUG_CORE
  1095. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1096. "Received notification about configuration update for `%s' with RIM %u.\n",
  1097. GNUNET_i2s (&cim->peer), (unsigned int) ntohl (cim->rim_id));
  1098. #endif
  1099. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &cim->peer.hashPubKey);
  1100. if (pr == NULL)
  1101. {
  1102. GNUNET_break (0);
  1103. reconnect_later (h);
  1104. return;
  1105. }
  1106. if (pr->rim_id != ntohl (cim->rim_id))
  1107. {
  1108. #if DEBUG_CORE
  1109. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1110. "Reservation ID mismatch in notification...\n");
  1111. #endif
  1112. break;
  1113. }
  1114. pcic = pr->pcic;
  1115. pr->pcic = NULL;
  1116. GNUNET_free_non_null (pr->pcic_ptr);
  1117. pr->pcic_ptr = NULL;
  1118. if (pcic != NULL)
  1119. pcic (pr->pcic_cls, &pr->peer, cim->bw_out, ntohl (cim->reserved_amount),
  1120. GNUNET_TIME_relative_ntoh (cim->reserve_delay),
  1121. GNUNET_ntohll (cim->preference));
  1122. break;
  1123. default:
  1124. reconnect_later (h);
  1125. return;
  1126. }
  1127. GNUNET_CLIENT_receive (h->client, &main_notify_handler, h,
  1128. GNUNET_TIME_UNIT_FOREVER_REL);
  1129. }
  1130. /**
  1131. * Task executed once we are done transmitting the INIT message.
  1132. * Starts our 'receive' loop.
  1133. *
  1134. * @param cls the 'struct GNUNET_CORE_Handle'
  1135. * @param success were we successful
  1136. */
  1137. static void
  1138. init_done_task (void *cls, int success)
  1139. {
  1140. struct GNUNET_CORE_Handle *h = cls;
  1141. if (success == GNUNET_SYSERR)
  1142. return; /* shutdown */
  1143. if (success == GNUNET_NO)
  1144. {
  1145. #if DEBUG_CORE
  1146. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1147. "Failed to exchange INIT with core, retrying\n");
  1148. #endif
  1149. if (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK)
  1150. reconnect_later (h);
  1151. return;
  1152. }
  1153. GNUNET_CLIENT_receive (h->client, &main_notify_handler, h,
  1154. GNUNET_TIME_UNIT_FOREVER_REL);
  1155. }
  1156. /**
  1157. * Our current client connection went down. Clean it up
  1158. * and try to reconnect!
  1159. *
  1160. * @param h our handle to the core service
  1161. */
  1162. static void
  1163. reconnect (struct GNUNET_CORE_Handle *h)
  1164. {
  1165. struct ControlMessage *cm;
  1166. struct InitMessage *init;
  1167. uint32_t opt;
  1168. uint16_t msize;
  1169. uint16_t *ts;
  1170. unsigned int hpos;
  1171. #if DEBUG_CORE
  1172. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting to CORE service\n");
  1173. #endif
  1174. GNUNET_assert (h->client == NULL);
  1175. GNUNET_assert (h->currently_down == GNUNET_YES);
  1176. h->client = GNUNET_CLIENT_connect ("core", h->cfg);
  1177. if (h->client == NULL)
  1178. {
  1179. reconnect_later (h);
  1180. return;
  1181. }
  1182. msize = h->hcnt * sizeof (uint16_t) + sizeof (struct InitMessage);
  1183. cm = GNUNET_malloc (sizeof (struct ControlMessage) + msize);
  1184. cm->cont = &init_done_task;
  1185. cm->cont_cls = h;
  1186. init = (struct InitMessage *) &cm[1];
  1187. init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT);
  1188. init->header.size = htons (msize);
  1189. opt = GNUNET_CORE_OPTION_SEND_CONNECT | GNUNET_CORE_OPTION_SEND_DISCONNECT;
  1190. if (h->status_events != NULL)
  1191. opt |= GNUNET_CORE_OPTION_SEND_STATUS_CHANGE;
  1192. if (h->inbound_notify != NULL)
  1193. {
  1194. if (h->inbound_hdr_only)
  1195. opt |= GNUNET_CORE_OPTION_SEND_HDR_INBOUND;
  1196. else
  1197. opt |= GNUNET_CORE_OPTION_SEND_FULL_INBOUND;
  1198. }
  1199. if (h->outbound_notify != NULL)
  1200. {
  1201. if (h->outbound_hdr_only)
  1202. opt |= GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND;
  1203. else
  1204. opt |= GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND;
  1205. }
  1206. init->options = htonl (opt);
  1207. ts = (uint16_t *) & init[1];
  1208. for (hpos = 0; hpos < h->hcnt; hpos++)
  1209. ts[hpos] = htons (h->handlers[hpos].type);
  1210. GNUNET_CONTAINER_DLL_insert (h->control_pending_head, h->control_pending_tail,
  1211. cm);
  1212. trigger_next_request (h, GNUNET_YES);
  1213. }
  1214. /**
  1215. * Connect to the core service. Note that the connection may
  1216. * complete (or fail) asynchronously.
  1217. *
  1218. * @param cfg configuration to use
  1219. * @param queue_size size of the per-peer message queue
  1220. * @param cls closure for the various callbacks that follow (including handlers in the handlers array)
  1221. * @param init callback to call on timeout or once we have successfully
  1222. * connected to the core service; note that timeout is only meaningful if init is not NULL
  1223. * @param connects function to call on peer connect, can be NULL
  1224. * @param disconnects function to call on peer disconnect / timeout, can be NULL
  1225. * @param status_events function to call on changes to peer connection status, can be NULL
  1226. * @param inbound_notify function to call for all inbound messages, can be NULL
  1227. * @param inbound_hdr_only set to GNUNET_YES if inbound_notify will only read the
  1228. * GNUNET_MessageHeader and hence we do not need to give it the full message;
  1229. * can be used to improve efficiency, ignored if inbound_notify is NULLL
  1230. * @param outbound_notify function to call for all outbound messages, can be NULL
  1231. * @param outbound_hdr_only set to GNUNET_YES if outbound_notify will only read the
  1232. * GNUNET_MessageHeader and hence we do not need to give it the full message
  1233. * can be used to improve efficiency, ignored if outbound_notify is NULLL
  1234. * @param handlers callbacks for messages we care about, NULL-terminated
  1235. * @return handle to the core service (only useful for disconnect until 'init' is called);
  1236. * NULL on error (in this case, init is never called)
  1237. */
  1238. struct GNUNET_CORE_Handle *
  1239. GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
  1240. unsigned int queue_size, void *cls,
  1241. GNUNET_CORE_StartupCallback init,
  1242. GNUNET_CORE_ConnectEventHandler connects,
  1243. GNUNET_CORE_DisconnectEventHandler disconnects,
  1244. GNUNET_CORE_PeerStatusEventHandler status_events,
  1245. GNUNET_CORE_MessageCallback inbound_notify,
  1246. int inbound_hdr_only,
  1247. GNUNET_CORE_MessageCallback outbound_notify,
  1248. int outbound_hdr_only,
  1249. const struct GNUNET_CORE_MessageHandler *handlers)
  1250. {
  1251. struct GNUNET_CORE_Handle *h;
  1252. h = GNUNET_malloc (sizeof (struct GNUNET_CORE_Handle));
  1253. h->cfg = cfg;
  1254. h->queue_size = queue_size;
  1255. h->cls = cls;
  1256. h->init = init;
  1257. h->connects = connects;
  1258. h->disconnects = disconnects;
  1259. h->status_events = status_events;
  1260. h->inbound_notify = inbound_notify;
  1261. h->outbound_notify = outbound_notify;
  1262. h->inbound_hdr_only = inbound_hdr_only;
  1263. h->outbound_hdr_only = outbound_hdr_only;
  1264. h->handlers = handlers;
  1265. h->hcnt = 0;
  1266. h->currently_down = GNUNET_YES;
  1267. h->peers = GNUNET_CONTAINER_multihashmap_create (128);
  1268. h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
  1269. while (handlers[h->hcnt].callback != NULL)
  1270. h->hcnt++;
  1271. GNUNET_assert (h->hcnt <
  1272. (GNUNET_SERVER_MAX_MESSAGE_SIZE -
  1273. sizeof (struct InitMessage)) / sizeof (uint16_t));
  1274. #if DEBUG_CORE
  1275. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service\n");
  1276. #endif
  1277. reconnect (h);
  1278. return h;
  1279. }
  1280. /**
  1281. * Disconnect from the core service. This function can only
  1282. * be called *after* all pending 'GNUNET_CORE_notify_transmit_ready'
  1283. * requests have been explicitly canceled.
  1284. *
  1285. * @param handle connection to core to disconnect
  1286. */
  1287. void
  1288. GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
  1289. {
  1290. struct ControlMessage *cm;
  1291. #if DEBUG_CORE
  1292. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from CORE service\n");
  1293. #endif
  1294. if (handle->cth != NULL)
  1295. {
  1296. GNUNET_CLIENT_notify_transmit_ready_cancel (handle->cth);
  1297. handle->cth = NULL;
  1298. }
  1299. while (NULL != (cm = handle->control_pending_head))
  1300. {
  1301. GNUNET_CONTAINER_DLL_remove (handle->control_pending_head,
  1302. handle->control_pending_tail, cm);
  1303. if (cm->th != NULL)
  1304. cm->th->cm = NULL;
  1305. if (cm->cont != NULL)
  1306. cm->cont (cm->cont_cls, GNUNET_SYSERR);
  1307. GNUNET_free (cm);
  1308. }
  1309. if (handle->client != NULL)
  1310. {
  1311. GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
  1312. handle->client = NULL;
  1313. }
  1314. GNUNET_CONTAINER_multihashmap_iterate (handle->peers,
  1315. &disconnect_and_free_peer_entry,
  1316. handle);
  1317. if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
  1318. {
  1319. GNUNET_SCHEDULER_cancel (handle->reconnect_task);
  1320. handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
  1321. }
  1322. GNUNET_CONTAINER_multihashmap_destroy (handle->peers);
  1323. handle->peers = NULL;
  1324. GNUNET_break (handle->ready_peer_head == NULL);
  1325. GNUNET_free (handle);
  1326. }
  1327. /**
  1328. * Task that calls 'request_next_transmission'.
  1329. *
  1330. * @param cls the 'struct PeerRecord*'
  1331. * @param tc scheduler context
  1332. */
  1333. static void
  1334. run_request_next_transmission (void *cls,
  1335. const struct GNUNET_SCHEDULER_TaskContext *tc)
  1336. {
  1337. struct PeerRecord *pr = cls;
  1338. pr->ntr_task = GNUNET_SCHEDULER_NO_TASK;
  1339. request_next_transmission (pr);
  1340. }
  1341. /**
  1342. * Ask the core to call "notify" once it is ready to transmit the
  1343. * given number of bytes to the specified "target". Must only be
  1344. * called after a connection to the respective peer has been
  1345. * established (and the client has been informed about this).
  1346. *
  1347. * @param handle connection to core service
  1348. * @param cork is corking allowed for this transmission?
  1349. * @param priority how important is the message?
  1350. * @param maxdelay how long can the message wait?
  1351. * @param target who should receive the message,
  1352. * use NULL for this peer (loopback)
  1353. * @param notify_size how many bytes of buffer space does notify want?
  1354. * @param notify function to call when buffer space is available
  1355. * @param notify_cls closure for notify
  1356. * @return non-NULL if the notify callback was queued,
  1357. * NULL if we can not even queue the request (insufficient
  1358. * memory); if NULL is returned, "notify" will NOT be called.
  1359. */
  1360. struct GNUNET_CORE_TransmitHandle *
  1361. GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle, int cork,
  1362. uint32_t priority,
  1363. struct GNUNET_TIME_Relative maxdelay,
  1364. const struct GNUNET_PeerIdentity *target,
  1365. size_t notify_size,
  1366. GNUNET_CONNECTION_TransmitReadyNotify notify,
  1367. void *notify_cls)
  1368. {
  1369. struct PeerRecord *pr;
  1370. struct GNUNET_CORE_TransmitHandle *th;
  1371. struct GNUNET_CORE_TransmitHandle *pos;
  1372. struct GNUNET_CORE_TransmitHandle *prev;
  1373. struct GNUNET_CORE_TransmitHandle *minp;
  1374. pr = GNUNET_CONTAINER_multihashmap_get (handle->peers, &target->hashPubKey);
  1375. if (NULL == pr)
  1376. {
  1377. /* attempt to send to peer that is not connected */
  1378. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1379. "Attempting to send to peer `%s' from peer `%s', but not connected!\n",
  1380. GNUNET_i2s (target), GNUNET_h2s (&handle->me.hashPubKey));
  1381. GNUNET_break (0);
  1382. return NULL;
  1383. }
  1384. GNUNET_assert (notify_size + sizeof (struct SendMessage) <
  1385. GNUNET_SERVER_MAX_MESSAGE_SIZE);
  1386. th = GNUNET_malloc (sizeof (struct GNUNET_CORE_TransmitHandle));
  1387. th->peer = pr;
  1388. GNUNET_assert (NULL != notify);
  1389. th->get_message = notify;
  1390. th->get_message_cls = notify_cls;
  1391. th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
  1392. th->priority = priority;
  1393. th->msize = notify_size;
  1394. th->cork = cork;
  1395. /* bound queue size */
  1396. if (pr->queue_size == handle->queue_size)
  1397. {
  1398. /* find lowest-priority entry, but skip the head of the list */
  1399. minp = pr->pending_head->next;
  1400. prev = minp;
  1401. while (prev != NULL)
  1402. {
  1403. if (prev->priority < minp->priority)
  1404. minp = prev;
  1405. prev = prev->next;
  1406. }
  1407. if (minp == NULL)
  1408. {
  1409. GNUNET_break (handle->queue_size != 0);
  1410. GNUNET_break (pr->queue_size == 1);
  1411. GNUNET_free (th);
  1412. #if DEBUG_CORE
  1413. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1414. "Dropping transmission request: cannot drop queue head and limit is one\n");
  1415. #endif
  1416. return NULL;
  1417. }
  1418. if (priority <= minp->priority)
  1419. {
  1420. #if DEBUG_CORE
  1421. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1422. "Dropping transmission request: priority too low\n");
  1423. #endif
  1424. GNUNET_free (th);
  1425. return NULL; /* priority too low */
  1426. }
  1427. GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, minp);
  1428. pr->queue_size--;
  1429. GNUNET_assert (0 == minp->get_message (minp->get_message_cls, 0, NULL));
  1430. GNUNET_free (minp);
  1431. }
  1432. /* Order entries by deadline, but SKIP 'HEAD' if
  1433. * we're in the 'ready_peer_*' DLL */
  1434. pos = pr->pending_head;
  1435. if ((pr->prev != NULL) || (pr->next != NULL) ||
  1436. (pr == handle->ready_peer_head))
  1437. {
  1438. GNUNET_assert (pos != NULL);
  1439. pos = pos->next; /* skip head */
  1440. }
  1441. /* insertion sort */
  1442. prev = pos;
  1443. while ((pos != NULL) && (pos->timeout.abs_value < th->timeout.abs_value))
  1444. {
  1445. prev = pos;
  1446. pos = pos->next;
  1447. }
  1448. GNUNET_CONTAINER_DLL_insert_after (pr->pending_head, pr->pending_tail, prev,
  1449. th);
  1450. pr->queue_size++;
  1451. /* was the request queue previously empty? */
  1452. #if DEBUG_CORE
  1453. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission request added to queue\n");
  1454. #endif
  1455. if ((pr->pending_head == th) && (pr->ntr_task == GNUNET_SCHEDULER_NO_TASK) &&
  1456. (pr->next == NULL) && (pr->prev == NULL) &&
  1457. (handle->ready_peer_head != pr))
  1458. pr->ntr_task =
  1459. GNUNET_SCHEDULER_add_now (&run_request_next_transmission, pr);
  1460. return th;
  1461. }
  1462. /**
  1463. * Cancel the specified transmission-ready notification.
  1464. *
  1465. * @param th handle that was returned by "notify_transmit_ready".
  1466. */
  1467. void
  1468. GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle *th)
  1469. {
  1470. struct PeerRecord *pr = th->peer;
  1471. struct GNUNET_CORE_Handle *h = pr->ch;
  1472. int was_head;
  1473. was_head = (pr->pending_head == th);
  1474. GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th);
  1475. pr->queue_size--;
  1476. if (th->cm != NULL)
  1477. {
  1478. /* we're currently in the control queue, remove */
  1479. GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
  1480. h->control_pending_tail, th->cm);
  1481. GNUNET_free (th->cm);
  1482. }
  1483. GNUNET_free (th);
  1484. if (was_head)
  1485. {
  1486. if ((pr->prev != NULL) || (pr->next != NULL) || (pr == h->ready_peer_head))
  1487. {
  1488. /* the request that was 'approved' by core was
  1489. * canceled before it could be transmitted; remove
  1490. * us from the 'ready' list */
  1491. GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr);
  1492. }
  1493. request_next_transmission (pr);
  1494. }
  1495. }
  1496. /* ****************** GNUNET_CORE_peer_request_connect ******************** */
  1497. /**
  1498. * Handle for a request to the core to connect to
  1499. * a particular peer. Can be used to cancel the request
  1500. * (before the 'cont'inuation is called).
  1501. */
  1502. struct GNUNET_CORE_PeerRequestHandle
  1503. {
  1504. /**
  1505. * Link to control message.
  1506. */
  1507. struct ControlMessage *cm;
  1508. /**
  1509. * Core handle used.
  1510. */
  1511. struct GNUNET_CORE_Handle *h;
  1512. /**
  1513. * Continuation to run when done.
  1514. */
  1515. GNUNET_CORE_ControlContinuation cont;
  1516. /**
  1517. * Closure for 'cont'.
  1518. */
  1519. void *cont_cls;
  1520. };
  1521. /**
  1522. * Continuation called when the control message was transmitted.
  1523. * Calls the original continuation and frees the remaining
  1524. * resources.
  1525. *
  1526. * @param cls the 'struct GNUNET_CORE_PeerRequestHandle'
  1527. * @param success was the request transmitted?
  1528. */
  1529. static void
  1530. peer_request_connect_cont (void *cls, int success)
  1531. {
  1532. struct GNUNET_CORE_PeerRequestHandle *ret = cls;
  1533. if (ret->cont != NULL)
  1534. ret->cont (ret->cont_cls, success);
  1535. GNUNET_free (ret);
  1536. }
  1537. /**
  1538. * Request that the core should try to connect to a particular peer.
  1539. * Once the request has been transmitted to the core, the continuation
  1540. * function will be called. Note that this does NOT mean that a
  1541. * connection was successfully established -- it only means that the
  1542. * core will now try. Successful establishment of the connection
  1543. * will be signalled to the 'connects' callback argument of
  1544. * 'GNUNET_CORE_connect' only. If the core service does not respond
  1545. * to our connection attempt within the given time frame, 'cont' will
  1546. * be called with the TIMEOUT reason code.
  1547. *
  1548. * @param h core handle
  1549. * @param peer who should we connect to
  1550. * @param cont function to call once the request has been completed (or timed out)
  1551. * @param cont_cls closure for cont
  1552. *
  1553. * @return NULL on error or already connected,
  1554. * otherwise handle for cancellation
  1555. */
  1556. struct GNUNET_CORE_PeerRequestHandle *
  1557. GNUNET_CORE_peer_request_connect (struct GNUNET_CORE_Handle *h,
  1558. const struct GNUNET_PeerIdentity *peer,
  1559. GNUNET_CORE_ControlContinuation cont,
  1560. void *cont_cls)
  1561. {
  1562. struct GNUNET_CORE_PeerRequestHandle *ret;
  1563. struct ControlMessage *cm;
  1564. struct ConnectMessage *msg;
  1565. if (NULL != GNUNET_CONTAINER_multihashmap_get (h->peers, &peer->hashPubKey))
  1566. {
  1567. #if DEBUG_CORE
  1568. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers are already connected!\n");
  1569. #endif
  1570. return NULL;
  1571. }
  1572. cm = GNUNET_malloc (sizeof (struct ControlMessage) +
  1573. sizeof (struct ConnectMessage));
  1574. msg = (struct ConnectMessage *) &cm[1];
  1575. msg->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_REQUEST_CONNECT);
  1576. msg->header.size = htons (sizeof (struct ConnectMessage));
  1577. msg->reserved = htonl (0);
  1578. msg->peer = *peer;
  1579. GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
  1580. h->control_pending_tail, cm);
  1581. ret = GNUNET_malloc (sizeof (struct GNUNET_CORE_PeerRequestHandle));
  1582. ret->h = h;
  1583. ret->cm = cm;
  1584. ret->cont = cont;
  1585. ret->cont_cls = cont_cls;
  1586. cm->cont = &peer_request_connect_cont;
  1587. cm->cont_cls = ret;
  1588. #if DEBUG_CORE
  1589. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queueing REQUEST_CONNECT request\n");
  1590. #endif
  1591. trigger_next_request (h, GNUNET_NO);
  1592. return ret;
  1593. }
  1594. /**
  1595. * Cancel a pending request to connect to a particular peer. Must not
  1596. * be called after the 'cont' function was invoked.
  1597. *
  1598. * @param req request handle that was returned for the original request
  1599. */
  1600. void
  1601. GNUNET_CORE_peer_request_connect_cancel (struct GNUNET_CORE_PeerRequestHandle
  1602. *req)
  1603. {
  1604. struct GNUNET_CORE_Handle *h = req->h;
  1605. struct ControlMessage *cm = req->cm;
  1606. #if DEBUG_CORE
  1607. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1608. "A CHANGE PREFERENCE request was cancelled!\n");
  1609. #endif
  1610. GNUNET_CONTAINER_DLL_remove (h->control_pending_head, h->control_pending_tail,
  1611. cm);
  1612. GNUNET_free (cm);
  1613. GNUNET_free (req);
  1614. }
  1615. /* ****************** GNUNET_CORE_peer_change_preference ******************** */
  1616. struct GNUNET_CORE_InformationRequestContext
  1617. {
  1618. /**
  1619. * Our connection to the service.
  1620. */
  1621. struct GNUNET_CORE_Handle *h;
  1622. /**
  1623. * Link to control message, NULL if CM was sent.
  1624. */
  1625. struct ControlMessage *cm;
  1626. /**
  1627. * Link to peer record.
  1628. */
  1629. struct PeerRecord *pr;
  1630. };
  1631. /**
  1632. * CM was sent, remove link so we don't double-free.
  1633. *
  1634. * @param cls the 'struct GNUNET_CORE_InformationRequestContext'
  1635. * @param success were we successful?
  1636. */
  1637. static void
  1638. change_preference_send_continuation (void *cls, int success)
  1639. {
  1640. struct GNUNET_CORE_InformationRequestContext *irc = cls;
  1641. irc->cm = NULL;
  1642. }
  1643. /**
  1644. * Obtain statistics and/or change preferences for the given peer.
  1645. *
  1646. * @param h core handle
  1647. * @param peer identifies the peer
  1648. * @param timeout after how long should we give up (and call "info" with NULL
  1649. * for "peer" to signal an error)?
  1650. * @param bw_out set to the current bandwidth limit (sending) for this peer,
  1651. * caller should set "bw_out" to "-1" to avoid changing
  1652. * the current value; otherwise "bw_out" will be lowered to
  1653. * the specified value; passing a pointer to "0" can be used to force
  1654. * us to disconnect from the peer; "bw_out" might not increase
  1655. * as specified since the upper bound is generally
  1656. * determined by the other peer!
  1657. * @param amount reserve N bytes for receiving, negative
  1658. * amounts can be used to undo a (recent) reservation;
  1659. * @param preference increase incoming traffic share preference by this amount;
  1660. * in the absence of "amount" reservations, we use this
  1661. * preference value to assign proportional bandwidth shares
  1662. * to all connected peers
  1663. * @param info function to call with the resulting configuration information
  1664. * @param info_cls closure for info
  1665. * @return NULL on error
  1666. */
  1667. struct GNUNET_CORE_InformationRequestContext *
  1668. GNUNET_CORE_peer_change_preference (struct GNUNET_CORE_Handle *h,
  1669. const struct GNUNET_PeerIdentity *peer,
  1670. struct GNUNET_TIME_Relative timeout,
  1671. struct GNUNET_BANDWIDTH_Value32NBO bw_out,
  1672. int32_t amount, uint64_t preference,
  1673. GNUNET_CORE_PeerConfigurationInfoCallback
  1674. info, void *info_cls)
  1675. {
  1676. struct GNUNET_CORE_InformationRequestContext *irc;
  1677. struct PeerRecord *pr;
  1678. struct RequestInfoMessage *rim;
  1679. struct ControlMessage *cm;
  1680. pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &peer->hashPubKey);
  1681. if (NULL == pr)
  1682. {
  1683. /* attempt to change preference on peer that is not connected */
  1684. GNUNET_assert (0);
  1685. return NULL;
  1686. }
  1687. if (pr->pcic != NULL)
  1688. {
  1689. /* second change before first one is done */
  1690. GNUNET_break (0);
  1691. return NULL;
  1692. }
  1693. irc = GNUNET_malloc (sizeof (struct GNUNET_CORE_InformationRequestContext));
  1694. irc->h = h;
  1695. irc->pr = pr;
  1696. cm = GNUNET_malloc (sizeof (struct ControlMessage) +
  1697. sizeof (struct RequestInfoMessage));
  1698. cm->cont = &change_preference_send_continuation;
  1699. cm->cont_cls = irc;
  1700. irc->cm = cm;
  1701. rim = (struct RequestInfoMessage *) &cm[1];
  1702. rim->header.size = htons (sizeof (struct RequestInfoMessage));
  1703. rim->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO);
  1704. rim->rim_id = htonl (pr->rim_id = h->rim_id_gen++);
  1705. rim->limit_outbound = bw_out;
  1706. rim->reserve_inbound = htonl (amount);
  1707. rim->preference_change = GNUNET_htonll (preference);
  1708. rim->peer = *peer;
  1709. #if DEBUG_CORE
  1710. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1711. "Queueing CHANGE PREFERENCE request for peer `%s' with RIM %u\n",
  1712. GNUNET_i2s (peer), (unsigned int) pr->rim_id);
  1713. #endif
  1714. GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
  1715. h->control_pending_tail, cm);
  1716. pr->pcic = info;
  1717. pr->pcic_cls = info_cls;
  1718. pr->pcic_ptr = irc; /* for free'ing irc */
  1719. if (NULL != h->client)
  1720. trigger_next_request (h, GNUNET_NO);
  1721. return irc;
  1722. }
  1723. /**
  1724. * Cancel request for getting information about a peer.
  1725. * Note that an eventual change in preference, trust or bandwidth
  1726. * assignment MAY have already been committed at the time,
  1727. * so cancelling a request is NOT sure to undo the original
  1728. * request. The original request may or may not still commit.
  1729. * The only thing cancellation ensures is that the callback
  1730. * from the original request will no longer be called.
  1731. *
  1732. * @param irc context returned by the original GNUNET_CORE_peer_get_info call
  1733. */
  1734. void
  1735. GNUNET_CORE_peer_change_preference_cancel (struct
  1736. GNUNET_CORE_InformationRequestContext
  1737. *irc)
  1738. {
  1739. struct GNUNET_CORE_Handle *h = irc->h;
  1740. struct PeerRecord *pr = irc->pr;
  1741. GNUNET_assert (pr->pcic_ptr == irc);
  1742. if (irc->cm != NULL)
  1743. {
  1744. GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
  1745. h->control_pending_tail, irc->cm);
  1746. GNUNET_free (irc->cm);
  1747. }
  1748. pr->pcic = NULL;
  1749. pr->pcic_cls = NULL;
  1750. pr->pcic_ptr = NULL;
  1751. GNUNET_free (irc);
  1752. }
  1753. /* end of core_api.c */