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.

cmUdpPort.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  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 "cmThread.h"
  11. #include <sys/socket.h>
  12. #include <netinet/in.h>
  13. #include <arpa/inet.h>
  14. #include <fcntl.h>
  15. #include <unistd.h> // close
  16. #include "cmUdpPort.h"
  17. #define cmUdp_SYS_ERR (-1)
  18. #define cmUdp_NULL_SOCK (-1)
  19. #ifndef HOST_NAME_MAX
  20. #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
  21. #endif
  22. enum
  23. {
  24. kIsConnectedUdpFl = 0x01,
  25. kIsBlockingUdpFl = 0x02,
  26. kQueueingUdpFl = 0x04
  27. };
  28. typedef struct
  29. {
  30. cmErr_t err;
  31. int sockH;
  32. cmUdpCallback_t cbFunc;
  33. void* cbArg;
  34. unsigned timeOutMs;
  35. unsigned flags;
  36. cmThreadH_t thH;
  37. cmTs1p1cH_t qH;
  38. unsigned recvBufByteCnt;
  39. char* tempBuf;
  40. unsigned timeOutCnt;
  41. unsigned recvCnt;
  42. unsigned queCbCnt;
  43. unsigned errCnt;
  44. struct sockaddr_in sockaddr;
  45. cmChar_t ntopBuf[ INET_ADDRSTRLEN+1 ]; // use INET6_ADDRSTRLEN for IPv6
  46. cmChar_t hnameBuf[ HOST_NAME_MAX+1 ];
  47. } cmUdp_t;
  48. cmUdpH_t cmUdpNullHandle = cmSTATIC_NULL_HANDLE;
  49. #define _cmUdpClear_errno() errno = 0
  50. cmUdp_t* _cmUdpHandleToPtr( cmUdpH_t h )
  51. {
  52. cmUdp_t* p = (cmUdp_t*)h.h;
  53. assert(p != NULL);
  54. return p;
  55. }
  56. cmUdpRC_t _cmUdpFinal( cmUdp_t* p )
  57. {
  58. cmUdpRC_t rc = kOkUdpRC;
  59. if( cmThreadIsValid(p->thH) )
  60. if( cmThreadDestroy(&p->thH) != kOkThRC )
  61. return cmErrMsg(&p->err,kThreadFailUdpRC,"Listener thread destroy failed.");
  62. if( cmTs1p1cIsValid(p->qH) )
  63. if( cmTs1p1cDestroy(&p->qH) != kOkThRC )
  64. cmErrMsg(&p->err,kQueueFailUdpRC,"Receive data queue destroy failed.");
  65. cmMemPtrFree(&p->tempBuf);
  66. // close the socket
  67. if( p->sockH != cmUdp_NULL_SOCK )
  68. {
  69. _cmUdpClear_errno();
  70. if( close(p->sockH) != 0 )
  71. cmErrSysMsg(&p->err,kSockCloseFailUdpRC,errno,"The socket close failed." );
  72. p->sockH = cmUdp_NULL_SOCK;
  73. }
  74. return rc;
  75. }
  76. cmUdpRC_t _cmUdpFree( cmUdp_t* p )
  77. {
  78. cmUdpRC_t rc;
  79. if((rc = _cmUdpFinal(p)) != kOkUdpRC )
  80. return rc;
  81. cmMemFree(p);
  82. return rc;
  83. }
  84. cmUdpRC_t _cmUdpInitAddr( cmUdp_t* p, const char* addrStr, cmUdpPort_t portNumber, struct sockaddr_in* retAddrPtr )
  85. {
  86. memset(retAddrPtr,0,sizeof(struct sockaddr_in));
  87. if( portNumber == kInvalidUdpPortNumber )
  88. return cmErrMsg(&p->err,kInvalidPortNumbUdpRC,"The port number %i cannot be used.",kInvalidUdpPortNumber);
  89. if( addrStr == NULL )
  90. retAddrPtr->sin_addr.s_addr = htonl(INADDR_ANY);
  91. else
  92. {
  93. _cmUdpClear_errno();
  94. if(inet_pton(AF_INET,addrStr,&retAddrPtr->sin_addr) == 0 )
  95. //if(( retAddrPtr->sin_addr.s_addr = inet_addr(addrStr)) == INADDR_NONE )
  96. return cmErrSysMsg(&p->err,kPtoNFailUdpRC,errno, "The network address string '%s' could not be converted to a netword address structure.",cmStringNullGuard(addrStr) );
  97. }
  98. //retAddrPtr->sin_len = sizeof(struct sockaddr_in);
  99. retAddrPtr->sin_family = AF_INET;
  100. retAddrPtr->sin_port = htons(portNumber);
  101. return kOkUdpRC;
  102. }
  103. cmUdpRC_t _cmUdpConnect( cmUdp_t* p, const char* remoteAddr, cmUdpPort_t remotePort )
  104. {
  105. struct sockaddr_in addr;
  106. cmUdpRC_t rc;
  107. // create the remote address
  108. if((rc = _cmUdpInitAddr(p, remoteAddr, remotePort, &addr )) != kOkUdpRC )
  109. return rc;
  110. _cmUdpClear_errno();
  111. // ... and connect this socket to the remote address/port
  112. if( connect(p->sockH, (struct sockaddr*)&addr, sizeof(addr)) == cmUdp_SYS_ERR )
  113. return cmErrSysMsg(&p->err,kSockConnectFailUdpRC, errno, "Socket connect failed." );
  114. p->flags = cmSetFlag(p->flags,kIsConnectedUdpFl);
  115. return rc;
  116. }
  117. cmUdpRC_t cmUdpAlloc( cmCtx_t* ctx, cmUdpH_t* hp )
  118. {
  119. cmUdpRC_t rc;
  120. if((rc = cmUdpFree(hp)) != kOkUdpRC )
  121. return rc;
  122. cmUdp_t* p = cmMemAllocZ(cmUdp_t,1);
  123. cmErrSetup(&p->err,&ctx->rpt,"UDP Port");
  124. p->sockH = cmUdp_NULL_SOCK;
  125. hp->h = p;
  126. return rc;
  127. }
  128. cmUdpRC_t cmUdpFree( cmUdpH_t* hp )
  129. {
  130. cmUdpRC_t rc = kOkUdpRC;
  131. if( hp == NULL || cmUdpIsValid(*hp)==false)
  132. return rc;
  133. cmUdp_t* p = _cmUdpHandleToPtr(*hp);
  134. if((rc = _cmUdpFree(p)) != kOkUdpRC )
  135. return rc;
  136. hp->h = NULL;
  137. return rc;
  138. }
  139. cmUdpRC_t cmUdpInit(
  140. cmUdpH_t h,
  141. cmUdpPort_t port,
  142. unsigned flags,
  143. cmUdpCallback_t cbFunc,
  144. void* cbArg,
  145. const char* remoteAddr,
  146. cmUdpPort_t remotePort,
  147. unsigned recvBufByteCnt,
  148. unsigned timeOutMs )
  149. {
  150. cmUdpRC_t rc;
  151. cmUdp_t* p = _cmUdpHandleToPtr(h);
  152. if((rc = _cmUdpFinal(p)) != kOkUdpRC )
  153. return rc;
  154. _cmUdpClear_errno();
  155. // get a handle to the socket
  156. if(( p->sockH = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == cmUdp_SYS_ERR )
  157. return cmErrSysMsg(&p->err, kSockCreateFailUdpRC, errno, "Socket create failed." );
  158. // create the local address
  159. if((rc = _cmUdpInitAddr(p, NULL, port, &p->sockaddr )) != kOkUdpRC )
  160. goto errLabel;
  161. // bind the socket to a local address/port
  162. if( (bind( p->sockH, (struct sockaddr*)&p->sockaddr, sizeof(p->sockaddr))) == cmUdp_SYS_ERR )
  163. {
  164. rc = cmErrSysMsg(&p->err,kSockBindFailUdpRC,errno,"Socket bind failed." );
  165. goto errLabel;
  166. }
  167. // if a remote addr was given connect this socket to it
  168. if( remoteAddr != NULL )
  169. if((rc = _cmUdpConnect(p,remoteAddr,remotePort)) != kOkUdpRC )
  170. goto errLabel;
  171. // if this socket should block
  172. if( cmIsFlag(flags,kBlockingUdpFl) )
  173. {
  174. struct timeval timeOut;
  175. // set the socket time out
  176. timeOut.tv_sec = timeOutMs/1000;
  177. timeOut.tv_usec = (timeOutMs - (timeOut.tv_sec * 1000)) * 1000;
  178. if( setsockopt( p->sockH, SOL_SOCKET, SO_RCVTIMEO, &timeOut, sizeof(timeOut) ) == cmUdp_SYS_ERR )
  179. {
  180. rc = cmErrSysMsg(&p->err,kSockOptSetFailUdpRC,errno, "Attempt to set the socket timeout failed." );
  181. goto errLabel;
  182. }
  183. p->flags = cmSetFlag(p->flags,kIsBlockingUdpFl);
  184. }
  185. else
  186. {
  187. int opts;
  188. // get the socket options flags
  189. if( (opts = fcntl(p->sockH,F_GETFL)) < 0 )
  190. {
  191. rc = cmErrSysMsg(&p->err,kSockOptSetFailUdpRC,errno, "Attempt to get the socket options flags failed." );
  192. goto errLabel;
  193. }
  194. opts = (opts | O_NONBLOCK);
  195. // set the socket options flags
  196. if(fcntl(p->sockH,F_SETFL,opts) < 0)
  197. {
  198. rc = cmErrSysMsg(&p->err,kSockOptSetFailUdpRC,errno, "Attempt to set the socket to non-blocking failed." );
  199. goto errLabel;
  200. }
  201. }
  202. // if broadcast option was requested.
  203. if( cmIsFlag(flags,kBroadcastUdpFl) )
  204. {
  205. int bcastFl = 1;
  206. if( setsockopt( p->sockH, SOL_SOCKET, SO_BROADCAST, &bcastFl, sizeof(bcastFl) ) == cmUdp_SYS_ERR )
  207. {
  208. rc = cmErrSysMsg(&p->err,kSockOptSetFailUdpRC,errno, "Attempt to set the socket broadcast attribute failed." );
  209. goto errLabel;
  210. }
  211. }
  212. if( recvBufByteCnt != 0 )
  213. p->tempBuf = cmMemAlloc(char,recvBufByteCnt );
  214. p->timeOutMs = timeOutMs;
  215. p->cbFunc = cbFunc;
  216. p->cbArg = cbArg;
  217. p->recvBufByteCnt = recvBufByteCnt;
  218. p->timeOutCnt = 0;
  219. p->recvCnt = 0;
  220. p->queCbCnt = 0;
  221. p->errCnt = 0;
  222. if( cmIsFlag(flags,kNoQueueUdpFl) == false )
  223. p->flags = cmSetFlag(p->flags,kQueueingUdpFl);
  224. errLabel:
  225. if( rc != kOkUdpRC )
  226. _cmUdpFree(p);
  227. return rc;
  228. }
  229. cmUdpRC_t cmUdpFinal( cmUdpH_t h )
  230. {
  231. cmUdp_t* p = _cmUdpHandleToPtr(h);
  232. return _cmUdpFinal(p);
  233. }
  234. bool cmUdpIsValid( cmUdpH_t h )
  235. { return h.h != NULL; }
  236. const struct sockaddr_in* cmUdpLocalAddr( cmUdpH_t h )
  237. {
  238. cmUdp_t* p = _cmUdpHandleToPtr(h);
  239. return &p->sockaddr;
  240. }
  241. cmUdpRC_t cmUdpConnect( cmUdpH_t h, const char* remoteAddr, cmUdpPort_t remotePort )
  242. {
  243. cmUdp_t* p = _cmUdpHandleToPtr(h);
  244. return _cmUdpConnect(p,remoteAddr,remotePort);
  245. }
  246. cmUdpRC_t cmUdpSend( cmUdpH_t h, const char* data, unsigned dataByteCnt )
  247. {
  248. cmUdp_t* p = _cmUdpHandleToPtr(h);
  249. _cmUdpClear_errno();
  250. if( cmIsFlag(p->flags,kIsConnectedUdpFl) == false )
  251. return cmErrMsg(&p->err,kNotConnectedUdpRC,"cmUdpSend() only works with connected sockets.");
  252. if( send( p->sockH, data, dataByteCnt, 0 ) == cmUdp_SYS_ERR )
  253. return cmErrSysMsg(&p->err,kSockSendFailUdpRC,errno,"Send failed.");
  254. return kOkUdpRC;
  255. }
  256. cmUdpRC_t cmUdpSendTo( cmUdpH_t h, const char* data, unsigned dataByteCnt, const struct sockaddr_in* remoteAddr )
  257. {
  258. cmUdp_t* p = _cmUdpHandleToPtr(h);
  259. _cmUdpClear_errno();
  260. if( sendto(p->sockH, data, dataByteCnt, 0, (struct sockaddr*)remoteAddr, sizeof(*remoteAddr)) == cmUdp_SYS_ERR )
  261. return cmErrSysMsg(&p->err,kSockSendFailUdpRC,errno,"SendTo failed.");
  262. return kOkUdpRC;
  263. }
  264. cmUdpRC_t cmUdpSend2( cmUdpH_t h, const char* data, unsigned dataByteCnt, const char* remoteAddr, cmUdpPort_t remotePort )
  265. {
  266. cmUdpRC_t rc;
  267. cmUdp_t* p = _cmUdpHandleToPtr(h);
  268. struct sockaddr_in addr;
  269. if((rc = _cmUdpInitAddr(p,remoteAddr,remotePort,&addr)) != kOkUdpRC )
  270. return rc;
  271. return cmUdpSendTo( h, data, dataByteCnt, &addr );
  272. }
  273. cmUdpRC_t cmUdpRecv( cmUdpH_t h, char* data, unsigned dataByteCnt, struct sockaddr_in* fromAddr, unsigned* recvByteCntPtr )
  274. {
  275. cmUdp_t* p = _cmUdpHandleToPtr(h);
  276. cmUdpRC_t rc = kOkUdpRC;
  277. ssize_t retVal = 0;
  278. socklen_t sizeOfRemoteAddr = fromAddr==NULL ? 0 : sizeof(struct sockaddr_in);
  279. _cmUdpClear_errno();
  280. if( recvByteCntPtr != NULL )
  281. *recvByteCntPtr = 0;
  282. if((retVal = recvfrom(p->sockH, data, dataByteCnt, 0, (struct sockaddr*)fromAddr, &sizeOfRemoteAddr )) == cmUdp_SYS_ERR )
  283. return cmErrSysMsg(&p->err,kSockRecvFailUdpRC,errno,"recvFrom() failed.");
  284. if( recvByteCntPtr != NULL )
  285. *recvByteCntPtr = retVal;
  286. return rc;
  287. }
  288. bool _cmUdpThreadCb(void* param)
  289. {
  290. cmUdp_t* p = (cmUdp_t*)param;
  291. fd_set rdSet;
  292. struct timeval timeOut;
  293. // setup the select() call
  294. FD_ZERO(&rdSet);
  295. FD_SET(p->sockH, &rdSet );
  296. timeOut.tv_sec = p->timeOutMs/1000;
  297. timeOut.tv_usec = (p->timeOutMs - (timeOut.tv_sec * 1000)) * 1000;
  298. // NOTE; select() takes the highest socket value plus one of all the sockets in all the sets.
  299. switch( select(p->sockH+1,&rdSet,NULL,NULL,&timeOut) )
  300. {
  301. case -1: // error
  302. if( errno != EINTR )
  303. cmErrSysMsg(&p->err,kSockSelectFailUdpRC,errno,"Select failed.");
  304. ++p->errCnt;
  305. break;
  306. case 0: // select() timed out
  307. ++p->timeOutCnt;
  308. break;
  309. case 1: // (> 0) count of ready descripters
  310. if( FD_ISSET(p->sockH,&rdSet) )
  311. {
  312. struct sockaddr_in remoteAddr;
  313. socklen_t addrByteCnt = sizeof(remoteAddr);
  314. ssize_t retByteCnt;
  315. _cmUdpClear_errno();
  316. ++p->recvCnt;
  317. // recv the incoming msg into p->tempBuf[]
  318. if(( retByteCnt = recvfrom( p->sockH, p->tempBuf, p->recvBufByteCnt, 0, (struct sockaddr*)&remoteAddr, &addrByteCnt )) == cmUdp_SYS_ERR )
  319. cmErrSysMsg(&p->err,kSockRecvFailUdpRC,errno,"recvfrom() failed.");
  320. else
  321. {
  322. // check for overflow
  323. if( retByteCnt == p->recvBufByteCnt )
  324. cmErrMsg(&p->err,kRecvBufOverflowUdpRC,"The receive buffer requires more than %i bytes.",p->recvBufByteCnt);
  325. else
  326. {
  327. // if queueing is enabled
  328. if( cmIsFlag(p->flags,kQueueingUdpFl ) )
  329. {
  330. // enqueue the msg - with the source address appended after the data
  331. const void* msgPtrArray[] = { p->tempBuf, &remoteAddr, p->tempBuf };
  332. unsigned msgByteCntArray[] = { retByteCnt, sizeof(remoteAddr) };
  333. if( cmTs1p1cEnqueueSegMsg( p->qH, msgPtrArray, msgByteCntArray, 2 ) != kOkThRC )
  334. cmErrMsg(&p->err,kQueueFailUdpRC,"A received msg containing %i bytes was not queued.",retByteCnt);
  335. }
  336. else // if queueing is not enabled - transmit the data directly via the callback
  337. if( p->cbFunc != NULL )
  338. {
  339. p->cbFunc(p->cbArg,p->tempBuf,retByteCnt,&remoteAddr);
  340. }
  341. }
  342. }
  343. }
  344. break;
  345. default:
  346. { assert(0); }
  347. } // switch
  348. return true;
  349. }
  350. cmRC_t _cmUdpQueueCb(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr )
  351. {
  352. cmUdp_t* p = (cmUdp_t*)userCbPtr;
  353. if( p->cbFunc != NULL )
  354. {
  355. struct sockaddr_in addr;
  356. assert( msgByteCnt >= sizeof(addr));
  357. const char* dataPtr = (const char*)msgDataPtr;
  358. // the address of the data source is apppended to the data bytes.
  359. const char* addrPtr = dataPtr + msgByteCnt - sizeof(addr);
  360. memcpy(&addr,addrPtr,sizeof(addr));
  361. // make the receive callback
  362. p->cbFunc(p->cbArg,dataPtr,msgByteCnt-sizeof(addr),&addr);
  363. ++p->queCbCnt;
  364. }
  365. return cmOkRC;
  366. }
  367. cmUdpRC_t cmUdpEnableListen( cmUdpH_t h, bool enableFl )
  368. {
  369. cmUdp_t* p = _cmUdpHandleToPtr(h);
  370. if( cmThreadIsValid(p->thH) == false && enableFl == true)
  371. {
  372. if(cmThreadCreate(&p->thH,_cmUdpThreadCb,p,p->err.rpt) != kOkThRC )
  373. return cmErrMsg(&p->err,kThreadFailUdpRC,"Listener thread create failed.");
  374. if(cmTs1p1cCreate(&p->qH,p->recvBufByteCnt,_cmUdpQueueCb,p,p->err.rpt) != kOkThRC )
  375. return cmErrMsg(&p->err,kQueueFailUdpRC,"Listener data queue create failed.");
  376. }
  377. if( cmThreadIsValid(p->thH) )
  378. if( cmThreadPause( p->thH, enableFl ? 0 : kPauseThFl ) != kOkThRC )
  379. return cmErrMsg(&p->err,kThreadFailUdpRC,"The listener thread failed to %s.", enableFl ? "pause" : "un-pause" );
  380. return kOkUdpRC;
  381. }
  382. bool cmUdpIsQueueEnabled( cmUdpH_t h )
  383. {
  384. cmUdp_t* p = _cmUdpHandleToPtr(h);
  385. return cmIsFlag(p->flags,kQueueingUdpFl);
  386. }
  387. void cmUdpQueueEnable( cmUdpH_t h, bool enableFl )
  388. {
  389. cmUdp_t* p = _cmUdpHandleToPtr(h);
  390. p->flags = cmSetFlag(p->flags,kQueueingUdpFl);
  391. }
  392. unsigned cmUdpAvailDataByteCount( cmUdpH_t h )
  393. {
  394. cmUdp_t* p = _cmUdpHandleToPtr(h);
  395. return cmTs1p1cIsValid(p->qH) ? cmTs1p1cDequeueMsgByteCount( p->qH ) : 0;
  396. }
  397. cmUdpRC_t cmUdpGetAvailData( cmUdpH_t h, char* data, unsigned* dataByteCntPtr, struct sockaddr_in* fromAddr )
  398. {
  399. cmUdp_t* p = _cmUdpHandleToPtr(h);
  400. unsigned availByteCnt;
  401. // if a received msg is queued
  402. if( (availByteCnt = cmTs1p1cAvailByteCount(p->qH)) > 0 )
  403. {
  404. // all msg's must have at least a source address
  405. assert( availByteCnt >= sizeof(*fromAddr) );
  406. // get the size of the return buffer (or 0 if there is no return buffer)
  407. unsigned dataByteCnt = (data != NULL && dataByteCntPtr != NULL) ? *dataByteCntPtr : 0;
  408. if( dataByteCnt == 0 )
  409. data = NULL;
  410. // dequeue the msg - if data==NULL then the data will be returned by
  411. // a call to the callback function provided in cmUdpAlloc().
  412. if( cmTs1p1cDequeueMsg(p->qH, data, dataByteCnt ) != kOkThRC )
  413. return cmErrMsg(&p->err,kQueueFailUdpRC,"Data dequeue failed.");
  414. // if a return buffer was given
  415. if( data != NULL )
  416. {
  417. assert( dataByteCntPtr != NULL );
  418. // the source address is appended to the end of the data
  419. const char* addrPtr = data + availByteCnt - sizeof(*fromAddr);
  420. // copy out the source address
  421. if( fromAddr != NULL )
  422. memcpy(fromAddr,addrPtr,sizeof(*fromAddr));
  423. // subtract the address size from the total msg size
  424. *dataByteCntPtr = availByteCnt - sizeof(*fromAddr);
  425. }
  426. }
  427. return kOkUdpRC;
  428. }
  429. void cmUdpReport( cmUdpH_t h, cmRpt_t* rpt )
  430. {
  431. cmUdp_t* p = _cmUdpHandleToPtr(h);
  432. cmRptPrintf(rpt,"time-out:%i recv:%i queue cb:%i\n",p->timeOutCnt,p->recvCnt,p->queCbCnt);
  433. }
  434. cmUdpRC_t cmUdpInitAddr( cmUdpH_t h, const char* addrStr, cmUdpPort_t portNumber, struct sockaddr_in* retAddrPtr )
  435. {
  436. cmUdp_t* p = _cmUdpHandleToPtr(h);
  437. return _cmUdpInitAddr(p,addrStr,portNumber,retAddrPtr);
  438. }
  439. const cmChar_t* cmUdpAddrToString( cmUdpH_t h, const struct sockaddr_in* addr )
  440. {
  441. cmUdp_t* p = _cmUdpHandleToPtr(h);
  442. _cmUdpClear_errno();
  443. if( inet_ntop(AF_INET, &(addr->sin_addr), p->ntopBuf, INET_ADDRSTRLEN) == NULL)
  444. {
  445. cmErrSysMsg(&p->err,kNtoPFailUdpRC,errno, "Network address to string conversion failed." );
  446. return NULL;
  447. }
  448. p->ntopBuf[INET_ADDRSTRLEN]=0;
  449. return p->ntopBuf;
  450. }
  451. bool cmUdpAddrIsEqual( const struct sockaddr_in* a0, const struct sockaddr_in* a1 )
  452. {
  453. return a0->sin_family == a1->sin_family
  454. && a0->sin_port == a1->sin_port
  455. && memcmp(&a0->sin_addr,&a1->sin_addr,sizeof(a0->sin_addr))==0;
  456. }
  457. const cmChar_t* cmUdpHostName( cmUdpH_t h )
  458. {
  459. cmUdp_t* p = _cmUdpHandleToPtr(h);
  460. _cmUdpClear_errno();
  461. if( gethostname(p->hnameBuf,HOST_NAME_MAX) != 0 )
  462. {
  463. cmErrSysMsg(&p->err,kHostNameFailUdpRC,errno, "gethostname() failed." );
  464. return NULL;
  465. }
  466. p->hnameBuf[HOST_NAME_MAX] = 0;
  467. return p->hnameBuf;
  468. }
  469. //=======================================================================================
  470. void cmUdpCallbackTest( void* cbArg, const char* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
  471. {
  472. printf("%s\n",data);
  473. }
  474. cmUdpRC_t cmUdpTest( cmCtx_t* ctx, const char* remoteIpAddr, cmUdpPort_t port )
  475. {
  476. cmUdpRC_t rc = kOkUdpRC;
  477. cmUdpH_t h = cmUdpNullHandle;
  478. cmErr_t* err = &ctx->err;
  479. unsigned recvBufByteCnt = 4096;
  480. unsigned recvTimeOutMs = 50;
  481. unsigned udpFlags = kNonBlockingUdpFl | kBroadcastUdpFl | kNoQueueUdpFl;
  482. unsigned strN = 1024;
  483. char str[ strN ];
  484. struct sockaddr_in addr;
  485. // allocate the UDP port
  486. if((rc = cmUdpAlloc(ctx, &h )) != kOkUdpRC )
  487. return cmErrMsg(err,rc,"UDP port allocate failed.");
  488. // initialize the UDP port
  489. if((rc = cmUdpInit( h, port, udpFlags, cmUdpCallbackTest, NULL, NULL, 0, recvBufByteCnt, recvTimeOutMs )) != kOkUdpRC )
  490. {
  491. rc = cmErrMsg(err,rc,"UPD port initialzation failed.");
  492. goto errLabel;
  493. }
  494. // convert the IP address to a sockaddr_in
  495. if((rc = cmUdpInitAddr(h, remoteIpAddr, port, &addr )) != kOkUdpRC )
  496. {
  497. rc = cmErrMsg(err,rc,"IP address conversion failed.");
  498. goto errLabel;
  499. }
  500. // start up the UDP port listening thread
  501. if((rc = cmUdpEnableListen(h, true )) != kOkUdpRC )
  502. {
  503. rc = cmErrMsg(err,rc,"UDP port switch to listen mode failed.");
  504. goto errLabel;
  505. }
  506. printf("q=quit");
  507. while(1)
  508. {
  509. printf("$");
  510. fflush(stdout);
  511. scanf("%s",str);
  512. if( strlen(str) > 0 )
  513. {
  514. if( strcmp(str,"q")==0 )
  515. break;
  516. if((rc = cmUdpSendTo(h,str,strlen(str)+1,&addr)) != kOkUdpRC )
  517. {
  518. rc = cmErrMsg(err,rc,"UDP send failed.");
  519. goto errLabel;
  520. }
  521. }
  522. }
  523. errLabel:
  524. if((rc = cmUdpFree(&h)) != kOkUdpRC )
  525. rc = cmErrMsg(err,rc,"UDP port free failed.");
  526. return rc;
  527. }
  528. cmUdpRC_t cmUdpTestV( cmCtx_t* ctx, unsigned argc, const char* argv[])
  529. {
  530. if( argc != 2 )
  531. return cmErrMsg(&ctx->err,kTestFailUdpRC,"cmUdpTestV usage: argv[0]=<IP Addr> argv[1]=<Socket Port Number>");
  532. const char* ipAddr = argv[0];
  533. cmUdpPort_t port = atoi(argv[1]);
  534. cmRptPrintf(&ctx->rpt,"UDP Test Sending To: %s port:%i\n",ipAddr,port);
  535. return cmUdpTest(ctx,ipAddr,port);
  536. }