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

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