networklayer_tcp.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. /*
  2. * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  3. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  4. */
  5. #include <stdlib.h> // malloc, free
  6. #ifdef _WIN32
  7. #include <malloc.h>
  8. #include <winsock2.h>
  9. #include <sys/types.h>
  10. #include <windows.h>
  11. #include <ws2tcpip.h>
  12. #define CLOSESOCKET(S) closesocket(S)
  13. #else
  14. #include <sys/select.h>
  15. #include <netinet/in.h>
  16. #include <netinet/tcp.h>
  17. #include <sys/socketvar.h>
  18. #include <sys/ioctl.h>
  19. #include <netdb.h> //gethostbyname for the client
  20. #define __USE_BSD
  21. #include <unistd.h> // read, write, close, usleep
  22. #define Sleep(x) usleep((x)*1000)
  23. #include <arpa/inet.h>
  24. #define CLOSESOCKET(S) close(S)
  25. #endif
  26. #include <stdio.h>
  27. #include <errno.h> // errno, EINTR
  28. #include <fcntl.h> // fcntl
  29. #include <string.h> // memset
  30. #include "networklayer_tcp.h" // UA_MULTITHREADING is defined in here
  31. #ifdef NOT_AMALGATED
  32. #include "ua_types.h" //TODO: this is a hack - refactor
  33. #include "ua_transport_generated.h" //TODO: this is a hack - refactor
  34. #include "ua_types_encoding_binary.h" //TODO: this is a hack - refactor
  35. #else
  36. #include "open62541.h"
  37. #endif
  38. #ifdef UA_MULTITHREADING
  39. #include <urcu/uatomic.h>
  40. #endif
  41. struct ServerNetworklayer_TCP;
  42. /* Forwarded to the server as a (UA_Connection) and used for callbacks back into
  43. the networklayer */
  44. typedef struct {
  45. UA_Connection connection;
  46. UA_Int32 sockfd;
  47. void *layer;
  48. } TCPConnection;
  49. /***************************/
  50. /* Server NetworkLayer TCP */
  51. /***************************/
  52. #define MAXBACKLOG 100
  53. /* Internal mapping of sockets to connections */
  54. typedef struct {
  55. TCPConnection *connection;
  56. #ifdef _WIN32
  57. UA_UInt32 sockfd;
  58. #else
  59. UA_Int32 sockfd;
  60. #endif
  61. } ConnectionLink;
  62. typedef struct ServerNetworkLayerTCP {
  63. UA_ConnectionConfig conf;
  64. fd_set fdset;
  65. #ifdef _WIN32
  66. UA_UInt32 serversockfd;
  67. UA_UInt32 highestfd;
  68. #else
  69. UA_Int32 serversockfd;
  70. UA_Int32 highestfd;
  71. #endif
  72. UA_UInt16 conLinksSize;
  73. ConnectionLink *conLinks;
  74. UA_UInt32 port;
  75. UA_String discoveryUrl;
  76. /* We remove the connection links only in the main thread. Attach
  77. to-be-deleted links with atomic operations */
  78. struct deleteLink {
  79. #ifdef _WIN32
  80. UA_UInt32 sockfd;
  81. #else
  82. UA_Int32 sockfd;
  83. #endif
  84. struct deleteLink *next;
  85. } *deleteLinkList;
  86. } ServerNetworkLayerTCP;
  87. typedef struct ClientNetworkLayerTCP {
  88. fd_set read_fds;
  89. #ifdef _WIN32
  90. UA_UInt32 sockfd;
  91. #else
  92. UA_Int32 sockfd;
  93. #endif
  94. } ClientNetworkLayerTCP;
  95. static UA_StatusCode setNonBlocking(int sockid) {
  96. #ifdef _WIN32
  97. u_long iMode = 1;
  98. if(ioctlsocket(sockid, FIONBIO, &iMode) != NO_ERROR)
  99. return UA_STATUSCODE_BADINTERNALERROR;
  100. #else
  101. int opts = fcntl(sockid,F_GETFL);
  102. if(opts < 0 || fcntl(sockid,F_SETFL,opts|O_NONBLOCK) < 0)
  103. return UA_STATUSCODE_BADINTERNALERROR;
  104. #endif
  105. return UA_STATUSCODE_GOOD;
  106. }
  107. static void freeConnectionCallback(UA_Server *server, TCPConnection *connection) {
  108. free(connection);
  109. }
  110. // after every select, reset the set of sockets we want to listen on
  111. static void setFDSet(ServerNetworkLayerTCP *layer) {
  112. FD_ZERO(&layer->fdset);
  113. FD_SET(layer->serversockfd, &layer->fdset);
  114. layer->highestfd = layer->serversockfd;
  115. for(UA_Int32 i=0;i<layer->conLinksSize;i++) {
  116. FD_SET(layer->conLinks[i].sockfd, &layer->fdset);
  117. if(layer->conLinks[i].sockfd > layer->highestfd)
  118. layer->highestfd = layer->conLinks[i].sockfd;
  119. }
  120. }
  121. // the callbacks are thread-safe if UA_MULTITHREADING is defined
  122. void closeConnection(TCPConnection *handle);
  123. void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf);
  124. static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
  125. setNonBlocking(newsockfd);
  126. TCPConnection *c = malloc(sizeof(TCPConnection));
  127. if(!c)
  128. return UA_STATUSCODE_BADINTERNALERROR;
  129. c->sockfd = newsockfd;
  130. c->layer = layer;
  131. c->connection.state = UA_CONNECTION_OPENING;
  132. c->connection.localConf = layer->conf;
  133. c->connection.channel = (void*)0;
  134. c->connection.close = (void (*)(void*))closeConnection;
  135. c->connection.write = (void (*)(void*, UA_ByteStringArray))writeCallback;
  136. layer->conLinks = realloc(layer->conLinks, sizeof(ConnectionLink)*(layer->conLinksSize+1));
  137. if(!layer->conLinks) {
  138. free(c);
  139. return UA_STATUSCODE_BADINTERNALERROR;
  140. }
  141. layer->conLinks[layer->conLinksSize].connection = c;
  142. layer->conLinks[layer->conLinksSize].sockfd = newsockfd;
  143. layer->conLinksSize++;
  144. return UA_STATUSCODE_GOOD;
  145. }
  146. /* Removes all connections from the network layer. Returns the work items to close them properly. */
  147. static UA_UInt32 removeAllConnections(ServerNetworkLayerTCP *layer, UA_WorkItem **returnWork) {
  148. UA_WorkItem *work;
  149. if (layer->conLinksSize <= 0 || !(work = malloc(sizeof(UA_WorkItem)*layer->conLinksSize))) {
  150. *returnWork = NULL;
  151. return 0;
  152. }
  153. #ifdef UA_MULTITHREADING
  154. struct deleteLink *d = uatomic_xchg(&layer->deleteLinkList, (void*)0);
  155. #else
  156. struct deleteLink *d = layer->deleteLinkList;
  157. layer->deleteLinkList = (void*)0;
  158. #endif
  159. UA_UInt32 count = 0;
  160. while(d) {
  161. UA_Int32 i;
  162. for(i = 0;i<layer->conLinksSize;i++) {
  163. if(layer->conLinks[i].sockfd == d->sockfd)
  164. break;
  165. }
  166. if(i < layer->conLinksSize) {
  167. TCPConnection *c = layer->conLinks[i].connection;
  168. layer->conLinksSize--;
  169. layer->conLinks[i] = layer->conLinks[layer->conLinksSize];
  170. work[count] = (UA_WorkItem)
  171. {.type = UA_WORKITEMTYPE_DELAYEDMETHODCALL,
  172. .work.methodCall = {.data = c,
  173. .method = (void (*)(UA_Server*,void*))freeConnectionCallback} };
  174. }
  175. struct deleteLink *oldd = d;
  176. d = d->next;
  177. free(oldd);
  178. count++;
  179. }
  180. *returnWork = work;
  181. return count;
  182. }
  183. #ifdef UA_MULTITHREADING
  184. void closeConnection(TCPConnection *handle) {
  185. if(uatomic_xchg(&handle->connection.state, UA_CONNECTION_CLOSING) == UA_CONNECTION_CLOSING)
  186. return;
  187. UA_Connection_detachSecureChannel(&handle->connection);
  188. shutdown(handle->sockfd,2);
  189. CLOSESOCKET(handle->sockfd);
  190. ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)handle->layer;
  191. // Remove the link later in the main thread
  192. struct deleteLink *d = malloc(sizeof(struct deleteLink));
  193. d->sockfd = handle->sockfd;
  194. while(1) {
  195. d->next = layer->deleteLinkList;
  196. if(uatomic_cmpxchg(&layer->deleteLinkList, d->next, d) == d->next)
  197. break;
  198. }
  199. }
  200. #else
  201. void closeConnection(TCPConnection *handle) {
  202. if(handle->connection.state == UA_CONNECTION_CLOSING)
  203. return;
  204. struct deleteLink *d = malloc(sizeof(struct deleteLink));
  205. if(!d)
  206. return;
  207. handle->connection.state = UA_CONNECTION_CLOSING;
  208. UA_Connection_detachSecureChannel(&handle->connection);
  209. shutdown(handle->sockfd,2);
  210. CLOSESOCKET(handle->sockfd);
  211. // Remove the link later in the main thread
  212. d->sockfd = handle->sockfd;
  213. ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)handle->layer;
  214. d->next = layer->deleteLinkList;
  215. layer->deleteLinkList = d;
  216. }
  217. #endif
  218. /** Accesses only the sockfd in the handle. Can be run from parallel threads. */
  219. void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf) {
  220. UA_UInt32 total_len = 0, nWritten = 0;
  221. #ifdef _WIN32
  222. LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
  223. memset(buf, 0, sizeof(gather_buf.stringsSize * sizeof(WSABUF)));
  224. int result = 0;
  225. for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
  226. buf[i].buf = (char*)gather_buf.strings[i].data;
  227. buf[i].len = gather_buf.strings[i].length;
  228. total_len += gather_buf.strings[i].length;
  229. }
  230. while(nWritten < total_len) {
  231. UA_UInt32 n = 0;
  232. do {
  233. result = WSASend(handle->sockfd, buf, gather_buf.stringsSize ,
  234. (LPDWORD)&n, 0, NULL, NULL);
  235. if(result != 0)
  236. printf("Error WSASend, code: %d \n", WSAGetLastError());
  237. } while(errno == EINTR);
  238. nWritten += n;
  239. }
  240. #else
  241. struct iovec iov[gather_buf.stringsSize];
  242. memset(iov, 0, sizeof(struct iovec)*gather_buf.stringsSize);
  243. for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
  244. iov[i].iov_base = gather_buf.strings[i].data;
  245. iov[i].iov_len = gather_buf.strings[i].length;
  246. total_len += gather_buf.strings[i].length;
  247. }
  248. struct msghdr message;
  249. memset(&message, 0, sizeof(message));
  250. message.msg_iov = iov;
  251. message.msg_iovlen = gather_buf.stringsSize;
  252. while (nWritten < total_len) {
  253. UA_Int32 n = 0;
  254. do {
  255. n = sendmsg(handle->sockfd, &message, 0);
  256. } while (n == -1L && errno == EINTR);
  257. nWritten += n;
  258. }
  259. #endif
  260. }
  261. static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger *logger) {
  262. #ifdef _WIN32
  263. if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == INVALID_SOCKET) {
  264. printf("ERROR opening socket, code: %d\n", WSAGetLastError());
  265. return UA_STATUSCODE_BADINTERNALERROR;
  266. }
  267. #else
  268. if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  269. perror("ERROR opening socket");
  270. return UA_STATUSCODE_BADINTERNALERROR;
  271. }
  272. #endif
  273. const struct sockaddr_in serv_addr = {
  274. .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
  275. .sin_port = htons(layer->port), .sin_zero = {0}};
  276. int optval = 1;
  277. if(setsockopt(layer->serversockfd, SOL_SOCKET,
  278. SO_REUSEADDR, (const char *)&optval,
  279. sizeof(optval)) == -1) {
  280. perror("setsockopt");
  281. CLOSESOCKET(layer->serversockfd);
  282. return UA_STATUSCODE_BADINTERNALERROR;
  283. }
  284. if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
  285. sizeof(serv_addr)) < 0) {
  286. perror("binding");
  287. CLOSESOCKET(layer->serversockfd);
  288. return UA_STATUSCODE_BADINTERNALERROR;
  289. }
  290. setNonBlocking(layer->serversockfd);
  291. listen(layer->serversockfd, MAXBACKLOG);
  292. char msg[256];
  293. sprintf(msg, "Listening on %.*s\n", layer->discoveryUrl.length, layer->discoveryUrl.data);
  294. UA_LOG_INFO((*logger), UA_LOGGERCATEGORY_SERVER, msg);
  295. return UA_STATUSCODE_GOOD;
  296. }
  297. static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_WorkItem **workItems,
  298. UA_UInt16 timeout) {
  299. UA_WorkItem *items = (void*)0;
  300. UA_Int32 itemsCount = removeAllConnections(layer, &items);
  301. setFDSet(layer);
  302. struct timeval tmptv = {0, timeout};
  303. UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
  304. if(resultsize < 0) {
  305. *workItems = items;
  306. return itemsCount;
  307. }
  308. // accept new connections (can only be a single one)
  309. if(FD_ISSET(layer->serversockfd,&layer->fdset)) {
  310. resultsize--;
  311. struct sockaddr_in cli_addr;
  312. socklen_t cli_len = sizeof(cli_addr);
  313. int newsockfd = accept(layer->serversockfd, (struct sockaddr *) &cli_addr, &cli_len);
  314. int i = 1;
  315. setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&i, sizeof(i));
  316. if (newsockfd >= 0)
  317. ServerNetworkLayerTCP_add(layer, newsockfd);
  318. }
  319. items = realloc(items, sizeof(UA_WorkItem)*(itemsCount+resultsize));
  320. // read from established sockets
  321. UA_Int32 j = itemsCount;
  322. UA_ByteString buf = { -1, NULL};
  323. for(UA_Int32 i=0;i<layer->conLinksSize && j<itemsCount+resultsize;i++) {
  324. if(!(FD_ISSET(layer->conLinks[i].sockfd, &layer->fdset)))
  325. continue;
  326. if(!buf.data) {
  327. buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
  328. if(!buf.data)
  329. break;
  330. }
  331. #ifdef _WIN32
  332. buf.length = recv(layer->conLinks[i].sockfd, (char *)buf.data,
  333. layer->conf.recvBufferSize, 0);
  334. #else
  335. buf.length = read(layer->conLinks[i].sockfd, buf.data, layer->conf.recvBufferSize);
  336. #endif
  337. if (buf.length <= 0) {
  338. closeConnection(layer->conLinks[i].connection); // work is returned in the next iteration
  339. } else {
  340. items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
  341. items[j].work.binaryNetworkMessage.message = buf;
  342. items[j].work.binaryNetworkMessage.connection = &layer->conLinks[i].connection->connection;
  343. buf.data = NULL;
  344. j++;
  345. }
  346. }
  347. if(buf.data)
  348. free(buf.data);
  349. if(j == 0) {
  350. free(items);
  351. *workItems = NULL;
  352. } else
  353. *workItems = items;
  354. return j;
  355. }
  356. static UA_Int32 ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP * layer, UA_WorkItem **workItems) {
  357. for(UA_Int32 index = 0;index < layer->conLinksSize;index++)
  358. closeConnection(layer->conLinks[index].connection);
  359. #ifdef _WIN32
  360. WSACleanup();
  361. #endif
  362. return removeAllConnections(layer, workItems);
  363. }
  364. static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
  365. UA_String_deleteMembers(&layer->discoveryUrl);
  366. for(UA_Int32 i=0;i<layer->conLinksSize;++i){
  367. free(layer->conLinks[i].connection);
  368. }
  369. free(layer->conLinks);
  370. free(layer);
  371. }
  372. UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
  373. #ifdef _WIN32
  374. WORD wVersionRequested;
  375. WSADATA wsaData;
  376. wVersionRequested = MAKEWORD(2, 2);
  377. WSAStartup(wVersionRequested, &wsaData);
  378. #endif
  379. ServerNetworkLayerTCP *tcplayer = malloc(sizeof(ServerNetworkLayerTCP));
  380. tcplayer->conf = conf;
  381. tcplayer->conLinksSize = 0;
  382. tcplayer->conLinks = NULL;
  383. tcplayer->port = port;
  384. tcplayer->deleteLinkList = (void*)0;
  385. char hostname[256];
  386. gethostname(hostname, 255);
  387. UA_String_copyprintf("opc.tcp://%s:%d", &tcplayer->discoveryUrl, hostname, port);
  388. UA_ServerNetworkLayer nl;
  389. nl.nlHandle = tcplayer;
  390. nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))ServerNetworkLayerTCP_start;
  391. nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16))ServerNetworkLayerTCP_getWork;
  392. nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**))ServerNetworkLayerTCP_stop;
  393. nl.free = (void (*)(void*))ServerNetworkLayerTCP_delete;
  394. nl.discoveryUrl = &tcplayer->discoveryUrl;
  395. return nl;
  396. }
  397. /***************************/
  398. /* Client NetworkLayer TCP */
  399. /***************************/
  400. static UA_StatusCode ClientNetworkLayerTCP_connect(const UA_String endpointUrl, ClientNetworkLayerTCP *resultHandle) {
  401. if(endpointUrl.length < 11 || endpointUrl.length >= 512) {
  402. printf("server url size invalid\n");
  403. return UA_STATUSCODE_BADINTERNALERROR;
  404. }
  405. if(strncmp((char*)endpointUrl.data, "opc.tcp://", 10) != 0) {
  406. printf("server url does not begin with opc.tcp://\n");
  407. return UA_STATUSCODE_BADINTERNALERROR;
  408. }
  409. //this is somewhat ugly, but atoi needs a c string
  410. char cstringEndpointUrl[endpointUrl.length+1];
  411. memcpy(cstringEndpointUrl, endpointUrl.data, endpointUrl.length);
  412. cstringEndpointUrl[endpointUrl.length+1] = '0';
  413. UA_UInt16 portpos = 9;
  414. UA_UInt16 port = 0;
  415. for(;portpos < endpointUrl.length; portpos++) {
  416. if(endpointUrl.data[portpos] == ':') {
  417. port = atoi(&cstringEndpointUrl[portpos+1]);
  418. break;
  419. }
  420. }
  421. if(port == 0) {
  422. printf("port invalid");
  423. return UA_STATUSCODE_BADINTERNALERROR;
  424. }
  425. char hostname[512];
  426. for(int i=10; i < portpos; i++)
  427. hostname[i-10] = endpointUrl.data[i];
  428. hostname[portpos-10] = 0;
  429. #ifdef _WIN32
  430. UA_UInt32 sock = 0;
  431. #else
  432. UA_Int32 sock = 0;
  433. #endif
  434. #ifdef _WIN32
  435. WORD wVersionRequested;
  436. WSADATA wsaData;
  437. wVersionRequested = MAKEWORD(2, 2);
  438. WSAStartup(wVersionRequested, &wsaData);
  439. if((sock = socket(PF_INET, SOCK_STREAM,0)) == INVALID_SOCKET) {
  440. #else
  441. if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  442. #endif
  443. printf("Could not create socket\n");
  444. return UA_STATUSCODE_BADINTERNALERROR;
  445. }
  446. struct hostent *server;
  447. server = gethostbyname(hostname);
  448. if (server == NULL) {
  449. printf("DNS lookup of %s failed\n", hostname);
  450. return UA_STATUSCODE_BADINTERNALERROR;
  451. }
  452. struct sockaddr_in server_addr;
  453. memset(&server_addr, 0, sizeof(server_addr));
  454. memcpy((char *)&server_addr.sin_addr.s_addr,
  455. (char *)server->h_addr_list[0],
  456. server->h_length);
  457. server_addr.sin_family = AF_INET;
  458. server_addr.sin_port = htons(port);
  459. if(connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
  460. printf("Connect failed.\n");
  461. return UA_STATUSCODE_BADINTERNALERROR;
  462. }
  463. //if(setNonBlocking(*sock) != UA_STATUSCODE_GOOD) {
  464. // printf("Could not switch to nonblocking.\n");
  465. // FINALLY
  466. // return UA_STATUSCODE_BADINTERNALERROR;
  467. //}
  468. resultHandle->sockfd = sock;
  469. return UA_STATUSCODE_GOOD;
  470. }
  471. static void ClientNetworkLayerTCP_disconnect(ClientNetworkLayerTCP* handle) {
  472. CLOSESOCKET(handle->sockfd);
  473. #ifdef _WIN32
  474. WSACleanup();
  475. #endif
  476. }
  477. static UA_StatusCode ClientNetworkLayerTCP_send(ClientNetworkLayerTCP *handle, UA_ByteStringArray gather_buf) {
  478. UA_UInt32 total_len = 0, nWritten = 0;
  479. #ifdef _WIN32
  480. LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
  481. int result = 0;
  482. for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
  483. buf[i].buf = (char*)gather_buf.strings[i].data;
  484. buf[i].len = gather_buf.strings[i].length;
  485. total_len += gather_buf.strings[i].length;
  486. }
  487. while(nWritten < total_len) {
  488. UA_UInt32 n = 0;
  489. do {
  490. result = WSASend(handle->sockfd, buf, gather_buf.stringsSize ,
  491. (LPDWORD)&n, 0, NULL, NULL);
  492. if(result != 0)
  493. printf("Error WSASend, code: %d \n", WSAGetLastError());
  494. } while(errno == EINTR);
  495. nWritten += n;
  496. }
  497. #else
  498. struct iovec iov[gather_buf.stringsSize];
  499. for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
  500. iov[i] = (struct iovec) {.iov_base = gather_buf.strings[i].data,
  501. .iov_len = gather_buf.strings[i].length};
  502. total_len += gather_buf.strings[i].length;
  503. }
  504. struct msghdr message = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = iov,
  505. .msg_iovlen = gather_buf.stringsSize, .msg_control = NULL,
  506. .msg_controllen = 0, .msg_flags = 0};
  507. while (nWritten < total_len) {
  508. int n = sendmsg(handle->sockfd, &message, 0);
  509. if(n <= -1)
  510. return UA_STATUSCODE_BADINTERNALERROR;
  511. nWritten += n;
  512. }
  513. #endif
  514. return UA_STATUSCODE_GOOD;
  515. }
  516. static UA_StatusCode ClientNetworkLayerTCP_awaitResponse(ClientNetworkLayerTCP *handle, UA_ByteString *response,
  517. UA_UInt32 timeout) {
  518. //FD_ZERO(&handle->read_fds);
  519. //FD_SET(handle->sockfd, &handle->read_fds);//tcp socket
  520. struct timeval tmptv = {0, timeout};
  521. /*int ret = select(handle->sockfd+1, &handle->read_fds, NULL, NULL, &tmptv);
  522. if(ret <= -1)
  523. return UA_STATUSCODE_BADINTERNALERROR;
  524. if(ret == 0)
  525. return UA_STATUSCODE_BADTIMEOUT;*/
  526. setsockopt(handle->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv,sizeof(struct timeval));
  527. int ret = 0;
  528. unsigned int already_received = 0;
  529. UA_SecureConversationMessageHeader msgHeader;
  530. do{
  531. ret = recv(handle->sockfd, (char*)(response->data+already_received), response->length-already_received, 0);
  532. if(ret <= -1){
  533. Sleep(100); //0.1 s
  534. continue;
  535. }
  536. if(ret == 0)
  537. return UA_STATUSCODE_BADSERVERNOTCONNECTED;
  538. //FIXME: receive even more
  539. if(ret <= 4){
  540. return UA_STATUSCODE_BADINTERNALERROR;
  541. }
  542. already_received+=ret;
  543. size_t offset = 0;
  544. //let us try to decode the length of the real message
  545. UA_SecureConversationMessageHeader_decodeBinary(response, &offset, &msgHeader);
  546. printf("ret %d, length %d, already recv %d\n", ret, msgHeader.messageHeader.messageSize, already_received);
  547. }while(msgHeader.messageHeader.messageSize == 0 || msgHeader.messageHeader.messageSize < already_received);
  548. response->length = already_received;
  549. return UA_STATUSCODE_GOOD;
  550. }
  551. static void ClientNetworkLayerTCP_delete(ClientNetworkLayerTCP *layer) {
  552. if(layer)
  553. free(layer);
  554. }
  555. UA_ClientNetworkLayer ClientNetworkLayerTCP_new(UA_ConnectionConfig conf) {
  556. ClientNetworkLayerTCP *tcplayer = malloc(sizeof(ClientNetworkLayerTCP));
  557. tcplayer->sockfd = 0;
  558. UA_ClientNetworkLayer layer;
  559. layer.nlHandle = tcplayer;
  560. layer.connect = (UA_StatusCode (*)(const UA_String, void**)) ClientNetworkLayerTCP_connect;
  561. layer.disconnect = (void (*)(void*)) ClientNetworkLayerTCP_disconnect;
  562. layer.delete = (void (*)(void*)) ClientNetworkLayerTCP_delete;
  563. layer.send = (UA_StatusCode (*)(void*, UA_ByteStringArray)) ClientNetworkLayerTCP_send;
  564. layer.awaitResponse = (UA_StatusCode (*)(void*, UA_ByteString *, UA_UInt32))ClientNetworkLayerTCP_awaitResponse;
  565. return layer;
  566. }