libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

cmUdpNet.c 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. #include "cmPrefix.h"
  4. #include "cmGlobal.h"
  5. #include "cmRpt.h"
  6. #include "cmErr.h"
  7. #include "cmCtx.h"
  8. #include "cmMem.h"
  9. #include "cmMallocDebug.h"
  10. #include "cmUdpPort.h"
  11. #include "cmJson.h"
  12. #include "cmUdpNet.h"
  13. #include "cmTime.h"
  14. typedef struct cmUdpNode_str
  15. {
  16. cmChar_t* label;
  17. unsigned id;
  18. struct sockaddr_in addr;
  19. cmUdpPort_t port;
  20. struct cmUdpNode_str* link;
  21. } cmUdpNode_t;
  22. typedef struct
  23. {
  24. cmErr_t err;
  25. cmUdpNetCallback_t cbFunc;
  26. void* cbArg;
  27. unsigned timeOutMs;
  28. unsigned nodeId;
  29. cmChar_t* nodeLabel;
  30. cmUdpNode_t* list;
  31. cmUdpH_t udpH;
  32. } cmUdpNet_t;
  33. cmUdpNetH_t cmUdpNetNullHandle = cmSTATIC_NULL_HANDLE;
  34. cmUdpNet_t* _cmUnHandleToPtr( cmUdpNetH_t h )
  35. {
  36. cmUdpNet_t* p = (cmUdpNet_t*)h.h;
  37. assert(p !=NULL );
  38. return p;
  39. }
  40. cmUnRC_t _cmUdpNetFinal( cmUdpNet_t* p )
  41. {
  42. // release the node list
  43. while( p->list != NULL)
  44. {
  45. cmUdpNode_t* np = p->list->link;
  46. cmMemFree(p->list->label);
  47. cmMemFree(p->list);
  48. p->list = np;
  49. }
  50. cmMemFree(p->nodeLabel);
  51. p->nodeLabel = NULL;
  52. p->cbFunc = NULL;
  53. p->cbArg = NULL;
  54. p->nodeId = cmInvalidId;
  55. return kOkUnRC;
  56. }
  57. cmUnRC_t _cmUdpNetFree( cmUdpNet_t* p )
  58. {
  59. cmUnRC_t rc;
  60. if((rc = _cmUdpNetFinal(p)) != kOkUnRC )
  61. return rc;
  62. // release the UDP port
  63. if( cmUdpFree(&p->udpH) != kOkUdpRC )
  64. return cmErrMsg(&p->err,kUdpPortFailUnRC,"The UDP port release failed.");
  65. cmMemFree(p);
  66. return kOkUnRC;
  67. }
  68. cmUdpNode_t* _cmUnFindLabel( cmUdpNet_t* p, const cmChar_t* label )
  69. {
  70. cmUdpNode_t* np = p->list;
  71. for(; np != NULL; np = np->link )
  72. if( strcmp(np->label,label) == 0 )
  73. return np;
  74. return NULL;
  75. }
  76. cmUdpNode_t* _cmUnFindId( cmUdpNet_t* p, unsigned id )
  77. {
  78. cmUdpNode_t* np = p->list;
  79. for(; np != NULL; np = np->link )
  80. if( np->id == id )
  81. return np;
  82. return NULL;
  83. }
  84. void _cmUdpNetCallback( void* cbArg, const char* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
  85. {
  86. cmUdpNet_t* p = (cmUdpNet_t*)cbArg;
  87. if( p->cbFunc != NULL )
  88. {
  89. cmUdpNetH_t h;
  90. cmUdpNode_t* np = p->list;
  91. h.h = p;
  92. // locate the source node in the node list to get the source node id
  93. for(; np != NULL; np = np->link)
  94. if( np->addr.sin_addr.s_addr == fromAddr->sin_addr.s_addr )
  95. {
  96. // forward the call to the networks callback function
  97. p->cbFunc(p->cbArg,h,data,dataByteCnt,np->id);
  98. break;
  99. }
  100. if( np == NULL )
  101. cmErrMsg(&p->err,kNodeNotFoundUnRC,"A callback source node could not be identified.");
  102. }
  103. }
  104. cmUnRC_t cmUdpNetAlloc(cmCtx_t* ctx, cmUdpNetH_t* hp)
  105. {
  106. cmUnRC_t rc;
  107. if((rc = cmUdpNetFree(hp)) != kOkUnRC )
  108. return rc;
  109. cmUdpNet_t* p = cmMemAllocZ(cmUdpNet_t,1);
  110. cmErrSetup(&p->err,&ctx->rpt,"UDP Network");
  111. if( cmUdpAlloc(ctx,&p->udpH) != kOkUdpRC )
  112. return cmErrMsg(&p->err,kUdpPortFailUnRC,"UDP port allocation failed.");
  113. p->nodeId = cmInvalidId;
  114. hp->h = p;
  115. return kOkUnRC;
  116. }
  117. cmUnRC_t cmUdpNetAllocJson(
  118. cmCtx_t* ctx,
  119. cmUdpNetH_t* hp,
  120. cmJsonH_t jsH,
  121. cmUdpNetCallback_t cbFunc,
  122. void* cbArg,
  123. unsigned flags)
  124. {
  125. cmUnRC_t rc;
  126. if((rc = cmUdpNetAlloc(ctx,hp)) != kOkUnRC )
  127. return rc;
  128. if((rc = cmUdpNetInitJson(*hp,jsH,cbFunc,cbArg)) != kOkUnRC )
  129. {
  130. if( cmIsFlag(flags,kNetOptionalUnFl) )
  131. rc = kOkUnRC;
  132. goto errLabel;
  133. }
  134. if((rc = cmUdpNetEnableListen(*hp,cmIsFlag(flags,kListenUnFl))) != kOkUnRC )
  135. goto errLabel;
  136. errLabel:
  137. if( rc != kOkUnRC )
  138. cmUdpNetFree(hp);
  139. return rc;
  140. }
  141. cmUnRC_t cmUdpNetFree( cmUdpNetH_t* hp )
  142. {
  143. cmUnRC_t rc = kOkUnRC;
  144. if( hp == NULL || cmUdpNetIsValid(*hp)==false )
  145. return kOkUnRC;
  146. cmUdpNet_t* p = _cmUnHandleToPtr(*hp);
  147. if((rc = _cmUdpNetFree(p)) != kOkUnRC )
  148. return rc;
  149. hp->h = NULL;
  150. return rc;
  151. }
  152. cmUnRC_t cmUdpNetInit(
  153. cmUdpNetH_t h,
  154. const cmChar_t* nodeLabel,
  155. unsigned nodeId,
  156. cmUdpPort_t nodeSocketPort,
  157. cmUdpNetCallback_t cbFunc,
  158. void* cbArg,
  159. unsigned recvBufByteCnt,
  160. unsigned socketRecvTimeOutMs )
  161. {
  162. cmUnRC_t rc;
  163. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  164. if((rc = _cmUdpNetFinal(p)) != kOkUnRC )
  165. return rc;
  166. // create the UDP port
  167. if( cmUdpInit(p->udpH,nodeSocketPort,kBlockingUdpFl,_cmUdpNetCallback,p,NULL,0,recvBufByteCnt,socketRecvTimeOutMs) != kOkUdpRC )
  168. {
  169. rc = cmErrMsg(&p->err,kUdpPortFailUnRC,"The UDP port create failed.");
  170. goto errLabel;
  171. }
  172. p->cbFunc = cbFunc;
  173. p->cbArg = cbArg;
  174. p->timeOutMs = socketRecvTimeOutMs;
  175. p->nodeId = nodeId;
  176. p->nodeLabel = cmMemAllocStr(nodeLabel);
  177. p->list = NULL;
  178. errLabel:
  179. if( rc != kOkUnRC )
  180. _cmUdpNetFinal(p);
  181. return rc;
  182. }
  183. cmUnRC_t _cmUnParseMemberErr( cmUdpNet_t* p, cmJsRC_t jsRC, const cmChar_t* errLabel, const cmChar_t* objectLabel )
  184. {
  185. if( jsRC == kNodeNotFoundJsRC && errLabel != NULL )
  186. return cmErrMsg(&p->err,kJsonFailUnRC,"The required field '%s'was not found in the UDP network resource tree in the object '%s'.",errLabel,cmStringNullGuard(objectLabel));
  187. return cmErrMsg(&p->err,kJsonFailUnRC,"JSON parsing failed on the UDP network resource object '%s'.",cmStringNullGuard(objectLabel));
  188. }
  189. cmUnRC_t cmUdpNetInitJson(
  190. cmUdpNetH_t h,
  191. cmJsonH_t jsH,
  192. cmUdpNetCallback_t cbFunc,
  193. void* cbArg)
  194. {
  195. cmUnRC_t rc;
  196. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  197. cmJsonNode_t* unp;
  198. cmJsonNode_t* nap;
  199. const cmChar_t* errLabelPtr = NULL;
  200. cmJsRC_t jsRC;
  201. unsigned port,recvBufByteCnt,timeOutMs;
  202. const cmChar_t* localLabel;
  203. const cmChar_t* topLabel = "udpnet";
  204. unsigned nodeCnt = 0;
  205. unsigned i;
  206. typedef struct
  207. {
  208. const cmChar_t* label;
  209. const cmChar_t* addr;
  210. unsigned id;
  211. } unNode_t;
  212. unNode_t* a = NULL;
  213. unNode_t* localPtr = NULL;
  214. if((rc = _cmUdpNetFinal(p)) != kOkUnRC )
  215. return rc;
  216. if((unp = cmJsonFindValue(jsH,topLabel,NULL,kObjectTId )) == NULL )
  217. {
  218. return cmErrMsg(&p->err,kJsonFailUnRC,"The JSON 'udpnet' element was not found.");
  219. }
  220. if(( jsRC = cmJsonMemberValues( unp, &errLabelPtr,
  221. "port", kIntTId, &port,
  222. "recvBufByteCnt", kIntTId, &recvBufByteCnt,
  223. "timeOutMs", kIntTId, &timeOutMs,
  224. "local", kStringTId,&localLabel,
  225. "nodeArray", kArrayTId, &nap,
  226. NULL )) != kOkJsRC )
  227. {
  228. rc = _cmUnParseMemberErr(p, jsRC, errLabelPtr, topLabel );
  229. goto errLabel;
  230. }
  231. // get a count of the number of nodes
  232. if((nodeCnt = cmJsonChildCount(nap)) == 0 )
  233. {
  234. rc = cmErrMsg(&p->err,kJsonFailUnRC,"The JSON 'udpnet' node array appears to be empty.");
  235. goto errLabel;
  236. }
  237. // allocate a temporary array to hold the node list
  238. a = cmMemAllocZ(unNode_t,nodeCnt);
  239. // for each remote node
  240. for(i=0; i<nodeCnt; ++i)
  241. {
  242. const cmJsonNode_t* naep = cmJsonArrayElementC(nap,i);
  243. // read the JSON recd
  244. if(( jsRC = cmJsonMemberValues( naep, &errLabelPtr,
  245. "label", kStringTId, &a[i].label,
  246. "id", kIntTId, &a[i].id,
  247. "addr", kStringTId, &a[i].addr,
  248. NULL )) != kOkJsRC )
  249. {
  250. rc = _cmUnParseMemberErr(p, jsRC, errLabelPtr, "nodeArray" );
  251. goto errLabel;
  252. }
  253. // track which node is the local node
  254. if( strcmp(localLabel,a[i].label) == 0 )
  255. localPtr = a + i;
  256. }
  257. // if no local node was located
  258. if( localPtr == NULL )
  259. {
  260. rc = cmErrMsg(&p->err, kJsonFailUnRC,"The local node label '%s' was not found.",cmStringNullGuard(localLabel));
  261. goto errLabel;
  262. }
  263. // initialize the network object
  264. if((rc = cmUdpNetInit(h,localPtr->label, localPtr->id, port, cbFunc, cbArg, recvBufByteCnt, timeOutMs )) != kOkUnRC )
  265. goto errLabel;
  266. // register each remote node
  267. for(i=0; i<nodeCnt; ++i)
  268. if( a + i != localPtr )
  269. if((rc = cmUdpNetRegisterRemote(h,a[i].label,a[i].id,a[i].addr,port)) != kOkUnRC )
  270. goto errLabel;
  271. errLabel:
  272. cmMemFree(a);
  273. if( rc != kOkUnRC )
  274. _cmUdpNetFinal(p);
  275. return rc;
  276. }
  277. bool cmUdpNetIsInitialized( cmUdpNetH_t h )
  278. {
  279. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  280. return p->nodeId != cmInvalidId;
  281. }
  282. cmUnRC_t cmUdpNetFinal( cmUdpNetH_t h )
  283. {
  284. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  285. return _cmUdpNetFinal(p);
  286. }
  287. cmUnRC_t cmUdpNetEnableListen( cmUdpNetH_t h, bool enableFl )
  288. {
  289. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  290. if( cmUdpEnableListen(p->udpH,enableFl) != kOkUdpRC )
  291. return cmErrMsg(&p->err,kUdpPortFailUnRC,"UDP port listen %s failed.",enableFl?"enable":"disable");
  292. return kOkUnRC;
  293. }
  294. bool cmUdpNetIsValid( cmUdpNetH_t h )
  295. { return h.h != NULL; }
  296. unsigned cmUdpNetLocalNodeId( cmUdpNetH_t h )
  297. {
  298. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  299. return p->nodeId;
  300. }
  301. const cmChar_t* cmUdpNetLocalNodeLabel( cmUdpNetH_t h )
  302. {
  303. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  304. return p->nodeLabel;
  305. }
  306. unsigned cmUdpNetNodeLabelToId( cmUdpNetH_t h, const cmChar_t* label )
  307. {
  308. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  309. // if the network was not initialized then nodeLabel == NULL
  310. if( p->nodeLabel == NULL )
  311. return cmInvalidId;
  312. // if 'label' refers to the local node
  313. if( strcmp(label,p->nodeLabel) == 0 )
  314. return p->nodeId;
  315. // otherwise search the remote node list
  316. cmUdpNode_t* np = p->list;
  317. for(; np != NULL; np = np->link )
  318. if( strcmp(np->label,label) == 0 )
  319. return np->id;
  320. return cmInvalidId;
  321. }
  322. const cmChar_t* cmUdpNetNodeIdToLabel( cmUdpNetH_t h, unsigned id )
  323. {
  324. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  325. // if 'id' refers to the local node
  326. if( id == p->nodeId )
  327. return p->nodeLabel;
  328. // otherwise search the remote node list
  329. cmUdpNode_t* np = p->list;
  330. for(; np != NULL; np = np->link )
  331. if( np->id == id )
  332. return np->label;
  333. return NULL;
  334. }
  335. unsigned cmUdpNetNodeCount( cmUdpNetH_t h )
  336. {
  337. unsigned cnt = 0;
  338. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  339. cmUdpNode_t* np = p->list;
  340. for(; np != NULL; np = np->link )
  341. ++cnt;
  342. return cnt;
  343. }
  344. unsigned cmUdpNetNodeId( cmUdpNetH_t h, unsigned nodeIdx )
  345. {
  346. unsigned cnt = 0;
  347. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  348. cmUdpNode_t* np = p->list;
  349. for(; np != NULL; np = np->link )
  350. if( cnt == nodeIdx )
  351. return np->id;
  352. return cmInvalidId;
  353. }
  354. cmUnRC_t cmUdpNetRegisterRemote(
  355. cmUdpNetH_t h,
  356. const cmChar_t* remoteNodeLabel,
  357. unsigned remoteNodeId,
  358. const char* remoteNodeSockAddr,
  359. cmUdpPort_t remoteNodePort )
  360. {
  361. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  362. struct sockaddr_in addr;
  363. if( remoteNodeLabel == NULL || strlen(remoteNodeLabel)==0 )
  364. return cmErrMsg(&p->err,kInvalidNodeLabelUnRC,"The node label must contain a non-empty string.");
  365. if( _cmUnFindLabel(p,remoteNodeLabel) != NULL )
  366. return cmErrMsg(&p->err,kDuplicateNodeLabelUnRC,"The node label '%s' is already in use.",cmStringNullGuard(remoteNodeLabel));
  367. if( _cmUnFindId(p,remoteNodeId) != NULL )
  368. return cmErrMsg(&p->err,kDuplicateNodeIdUnRC,"The node id '%i' is already in use.",remoteNodeId);
  369. if( cmUdpInitAddr(p->udpH, remoteNodeSockAddr, remoteNodePort, &addr ) != kOkUdpRC )
  370. return cmErrMsg(&p->err,kInvalidNodeAddrUnRC,"The node address '%s' port:%i is not valid.",cmStringNullGuard(remoteNodeSockAddr),remoteNodePort);
  371. cmUdpNode_t* np = cmMemAllocZ(cmUdpNode_t,1);
  372. np->label = cmMemAllocStr(remoteNodeLabel);
  373. np->id = remoteNodeId;
  374. np->addr = addr;
  375. np->port = remoteNodePort;
  376. np->link = p->list;
  377. p->list = np;
  378. return kOkUnRC;
  379. }
  380. cmUnRC_t cmUdpNetSendById( cmUdpNetH_t h, unsigned remoteNodeId, const void* data, unsigned dataByteCnt )
  381. {
  382. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  383. cmUdpNode_t* np;
  384. if((np = _cmUnFindId(p,remoteNodeId)) == NULL )
  385. return cmErrMsg(&p->err,kNodeNotFoundUnRC,"The remote node (id=%i) was not found.",remoteNodeId);
  386. if( cmUdpSendTo(p->udpH, data, dataByteCnt, &np->addr ) != kOkUdpRC )
  387. return cmErrMsg(&p->err,kSendFailUnRC,"An attempt to send to a remote node with id=%i failed.",remoteNodeId);
  388. return kOkUnRC;
  389. }
  390. cmUnRC_t cmUdpNetSendByLabel( cmUdpNetH_t h, const cmChar_t* remoteNodeLabel, const void* data, unsigned dataByteCnt )
  391. {
  392. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  393. cmUdpNode_t* np;
  394. if((np = _cmUnFindLabel(p,remoteNodeLabel)) == NULL )
  395. return cmErrMsg(&p->err,kNodeNotFoundUnRC,"The remote node (label=%s) was not found.",cmStringNullGuard(remoteNodeLabel));
  396. if( cmUdpSendTo(p->udpH, data, dataByteCnt, &np->addr ) != kOkUdpRC )
  397. return cmErrMsg(&p->err,kSendFailUnRC,"An attempt to send to the remote node labeled:%s failed.",cmStringNullGuard(remoteNodeLabel));
  398. return kOkUnRC;
  399. }
  400. cmUnRC_t cmUdpNetReceive( cmUdpNetH_t h, unsigned* msgCntPtr )
  401. {
  402. cmUnRC_t rc = kOkUnRC;
  403. unsigned maxMsgCnt = 0;
  404. unsigned msgCnt = 0;
  405. if( msgCntPtr == NULL )
  406. maxMsgCnt = cmInvalidCnt;
  407. else
  408. maxMsgCnt = *msgCntPtr;
  409. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  410. if( cmUdpIsValid(p->udpH ) )
  411. {
  412. for(msgCnt=0; (maxMsgCnt==cmInvalidCnt || msgCnt<maxMsgCnt) && cmUdpAvailDataByteCount(p->udpH); ++msgCnt )
  413. {
  414. if( cmUdpGetAvailData(p->udpH,NULL,NULL,NULL) != kOkUdpRC )
  415. {
  416. rc = cmErrMsg(&p->err,kGetDataFailUnRC,"An attempt to get available message data failed.");
  417. break;
  418. }
  419. }
  420. }
  421. if( msgCntPtr != NULL )
  422. *msgCntPtr = msgCnt;
  423. return rc;
  424. }
  425. cmUnRC_t cmUdpNetPrintNodes( cmUdpNetH_t h, cmRpt_t* rpt )
  426. {
  427. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  428. cmUdpNode_t* np = p->list;
  429. unsigned i;
  430. for(i=0; np != NULL; np = np->link, ++i )
  431. cmRptPrintf(rpt,"%5i %5i %s\n",i,np->id,np->label);
  432. return kOkUnRC;
  433. }
  434. void cmUdpNetReport( cmUdpNetH_t h, cmRpt_t* rpt )
  435. {
  436. cmUdpNet_t* p = _cmUnHandleToPtr(h);
  437. cmUdpReport(p->udpH,rpt);
  438. }
  439. //=========================================================================================
  440. typedef struct
  441. {
  442. cmTimeSpec_t t;
  443. unsigned localNodeId;
  444. cmUdpNetH_t h;
  445. } _cmUdpNetTestMsg_t;
  446. void _cmUdpNetTestCb( void* cbArg, cmUdpNetH_t h, const char* data, unsigned dataByteCnt, unsigned remoteNodeId )
  447. {
  448. cmRpt_t* rpt = (cmRpt_t*)cbArg;
  449. cmRptPrintf(rpt,"recv - id:%i %s\n",remoteNodeId, data);
  450. }
  451. void _cmUdpNetTestCb2( void* cbArg, cmUdpNetH_t h, const char* data, unsigned dataByteCnt, unsigned remoteNodeId )
  452. {
  453. _cmUdpNetTestMsg_t* m = (_cmUdpNetTestMsg_t*)data;
  454. cmRpt_t* rpt = (cmRpt_t*)cbArg;
  455. assert( dataByteCnt == sizeof(_cmUdpNetTestMsg_t));
  456. if( m->localNodeId == cmUdpNetLocalNodeId(h) )
  457. {
  458. cmTimeSpec_t t;
  459. cmTimeGet(&t);
  460. cmRptPrintf(rpt,"elapsed:%i\n", cmTimeElapsedMicros(&m->t,&t));
  461. }
  462. else
  463. {
  464. cmRptPrintf(rpt,"echo\n");
  465. cmUdpNetSendById(h,m->localNodeId,&m,sizeof(*m));
  466. }
  467. }
  468. const cmChar_t* _cmUdpNetTestGetOpt( int argc, const char* argv[], const char* opt )
  469. {
  470. unsigned i;
  471. for(i=0; i<argc; ++i)
  472. if( strcmp(argv[i],opt) == 0 )
  473. return argv[i+1];
  474. return NULL;
  475. }
  476. cmRC_t cmUdpNetTest( cmCtx_t* ctx, int argc, const char* argv[] )
  477. {
  478. cmUdpNetH_t h = cmUdpNetNullHandle;
  479. cmJsonH_t jsH = cmJsonNullHandle;
  480. cmErr_t err;
  481. cmRC_t rc = cmOkRC;
  482. unsigned i = 0;
  483. const cmChar_t* jsonFn;
  484. const cmChar_t* remoteNodeLabel;
  485. unsigned strCharCnt = 31;
  486. cmChar_t str[ strCharCnt + 1 ];
  487. bool msgFl = false;
  488. enum { kUdpNetTestErrRC = 1 };
  489. cmErrSetup(&err,&ctx->rpt,"UDP Net Test");
  490. // get the JSON file name
  491. if(( jsonFn = _cmUdpNetTestGetOpt(argc,argv,"-j")) == NULL)
  492. return cmErrMsg(&err,kUdpNetTestErrRC,"No JSON file name was given.");
  493. // get the remote node label to send too
  494. if(( remoteNodeLabel= _cmUdpNetTestGetOpt(argc,argv,"-n")) == NULL )
  495. return cmErrMsg(&err,kUdpNetTestErrRC,"No remote node label was given.");
  496. // create the JSON tree
  497. if( cmJsonInitializeFromFile(&jsH, jsonFn, ctx ) != kOkJsRC )
  498. {
  499. rc = cmErrMsg(&err,kUdpNetTestErrRC,"JSON file init failed on '%s'.",cmStringNullGuard(jsonFn));
  500. goto errLabel;
  501. }
  502. if( msgFl )
  503. {
  504. // alloc/init and put the network into listening mode
  505. if( cmUdpNetAllocJson(ctx,&h,jsH,_cmUdpNetTestCb2,&ctx->rpt,kListenUnFl) != kOkUnRC )
  506. {
  507. rc = cmErrMsg(&err,kUdpNetTestErrRC,"UDP alloc/init/listen failed.");
  508. goto errLabel;
  509. }
  510. }
  511. else
  512. {
  513. if( cmUdpNetAlloc(ctx,&h) != kOkUnRC )
  514. return cmErrMsg(&err,kUdpNetTestErrRC,"UDP alloc failed.");
  515. if( cmUdpNetInitJson(h,jsH,_cmUdpNetTestCb,&ctx->rpt) != kOkUnRC )
  516. {
  517. rc = cmErrMsg(&err,kUdpNetTestErrRC,"UDP net init failed.");
  518. goto errLabel;
  519. }
  520. if( cmUdpNetEnableListen(h,true) != kOkUnRC )
  521. {
  522. rc = cmErrMsg(&err,kUdpNetTestErrRC,"UDP listen enable failed.");
  523. goto errLabel;
  524. }
  525. }
  526. cmRptPrintf(&ctx->rpt,"s=send p=print r=report\n");
  527. char c;
  528. while((c=getchar()) != 'q')
  529. {
  530. bool promptFl = true;
  531. switch(c)
  532. {
  533. case 's':
  534. {
  535. // form the emessage
  536. snprintf(str,strCharCnt,"msg=%i",i);
  537. // send a message to the remote node
  538. if( !msgFl )
  539. if( cmUdpNetSendByLabel(h,remoteNodeLabel,str,strlen(str)+1 ) != kOkUnRC )
  540. cmErrMsg(&err,kUdpNetTestErrRC,"UDP net send failed.");
  541. ++i;
  542. }
  543. break;
  544. case 't':
  545. {
  546. _cmUdpNetTestMsg_t m;
  547. cmTimeGet(&m.t);
  548. m.localNodeId = cmUdpNetLocalNodeId(h);
  549. m.h = h;
  550. // send a message to the remote node
  551. if( msgFl )
  552. if( cmUdpNetSendByLabel(h,remoteNodeLabel,&m,sizeof(m) ) != kOkUnRC )
  553. cmErrMsg(&err,kUdpNetTestErrRC,"UDP net send failed.");
  554. }
  555. break;
  556. case 'p':
  557. cmUdpNetPrintNodes(h,&ctx->rpt);
  558. break;
  559. case 'r':
  560. cmUdpNetReport(h,&ctx->rpt);
  561. break;
  562. default:
  563. promptFl = false;
  564. }
  565. cmUdpNetReceive(h,NULL);
  566. if( promptFl )
  567. cmRptPrintf(&ctx->rpt,"%i> ",i);
  568. }
  569. errLabel:
  570. if( cmUdpNetFree(&h) != kOkUnRC )
  571. rc = cmErrMsg(&err,kUdpNetTestErrRC,"UDP free failed.");
  572. if( cmJsonFinalize(&jsH) != kOkJsRC )
  573. rc = cmErrMsg(&err,kUdpNetTestErrRC,"JSON final fail.");
  574. return rc;
  575. }