libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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. }