libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

cmUdpPort.c 19KB

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