UA_stack.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <sys/socketvar.h>
  5. #include <unistd.h> // read, write, close
  6. #include <errno.h> // errno, EINTR
  7. #include <memory.h> // memset
  8. #include <pthread.h>
  9. #include "UA_stack.h"
  10. #include "opcua_transportLayer.h"
  11. UA_TL_Description UA_TransportLayerDescriptorTcpBinary = {
  12. UA_TL_ENCODING_BINARY,
  13. UA_TL_CONNECTIONTYPE_TCPV4,
  14. UA_TL_MAXCONNECTIONS_DEFAULT,
  15. {-1,8192,8192,16384,1}
  16. };
  17. // TODO: do we really need a variable global to the module?
  18. UA_TL_data theTL;
  19. /** the tcp reader thread **/
  20. void* UA_TL_TCP_reader(void *p) {
  21. UA_TL_connection* c = (UA_TL_connection*) p;
  22. UA_ByteString readBuffer;
  23. UA_alloc((void**)&(readBuffer.data),c->localConf.recvBufferSize);
  24. while (c->connectionState != connectionState_CLOSE) {
  25. readBuffer.length = read(c->connectionHandle, readBuffer.data, c->localConf.recvBufferSize);
  26. printf("UA_TL_TCP_reader - %*.s ",c->remoteEndpointUrl.length,c->remoteEndpointUrl.data);
  27. UA_ByteString_printx("received=",&readBuffer);
  28. if (readBuffer.length > 0) {
  29. TL_process(c,&readBuffer);
  30. } else {
  31. c->connectionState = connectionState_CLOSE;
  32. perror("ERROR reading from socket1");
  33. }
  34. }
  35. // clean up: socket, buffer, connection
  36. // free resources allocated with socket
  37. printf("UA_TL_TCP_reader - shutdown\n");
  38. shutdown(c->connectionHandle,2);
  39. close(c->connectionHandle);
  40. c->connectionState = connectionState_CLOSED;
  41. UA_ByteString_deleteMembers(&readBuffer);
  42. // FIXME: standard C has no lambdas, we need a matcher with two arguments
  43. // UA_list_Element* lec = UA_list_findFirst(theTL,c,compare);
  44. // TODO: can we get get rid of reference to theTL?
  45. UA_list_Element* lec = UA_list_find(&theTL.connections,UA_NULL);
  46. UA_list_removeElement(lec,UA_NULL);
  47. UA_free(c);
  48. return UA_NULL;
  49. }
  50. /** write to a tcp transport layer connection */
  51. UA_Int32 UA_TL_TCP_write(struct T_TL_connection* c, UA_ByteString* msg) {
  52. UA_ByteString_printx("write data:", msg);
  53. int nWritten = 0;
  54. while (nWritten < msg->length) {
  55. int n;
  56. do {
  57. n = write(c->connectionHandle, &(msg->data[n]), msg->length-n);
  58. } while (n == -1L && errno == EINTR);
  59. if (n >= 0) {
  60. nWritten += n;
  61. } else {
  62. // TODO: error handling
  63. }
  64. }
  65. return UA_SUCCESS;
  66. }
  67. /** the tcp listener thread **/
  68. void* UA_TL_TCP_listen(void *p) {
  69. UA_TL_data* tld = (UA_TL_data*) p;
  70. UA_String_printf("open62541-server at ",&(tld->endpointUrl));
  71. while (UA_TRUE) {
  72. listen(tld->listenerHandle, tld->tld->maxConnections);
  73. // accept only if not max number of connections exceeded
  74. if (tld->tld->maxConnections == -1 || tld->connections.size < tld->tld->maxConnections) {
  75. struct sockaddr_in cli_addr;
  76. socklen_t cli_len = sizeof(cli_addr);
  77. int newsockfd = accept(tld->listenerHandle, (struct sockaddr *) &cli_addr, &cli_len);
  78. if (newsockfd < 0) {
  79. perror("ERROR on accept");
  80. } else {
  81. UA_TL_connection* c;
  82. UA_Int32 retval = UA_SUCCESS;
  83. retval |= UA_alloc((void**)&c,sizeof(UA_TL_connection));
  84. TL_Connection_init(c, tld);
  85. c->connectionHandle = newsockfd;
  86. c->UA_TL_writer = UA_TL_TCP_write;
  87. // add to list
  88. UA_list_addPayloadToBack(&(tld->connections),c);
  89. // TODO: handle retval of pthread_create
  90. pthread_create( &(c->readerThread), NULL, UA_TL_TCP_reader, (void*) c);
  91. }
  92. } else {
  93. // no action necessary to reject connection
  94. }
  95. }
  96. return UA_NULL;
  97. }
  98. UA_Int32 UA_TL_TCP_init(UA_TL_data* tld, UA_Int32 port) {
  99. UA_Int32 retval = UA_SUCCESS;
  100. // socket variables
  101. int optval = 1;
  102. struct sockaddr_in serv_addr;
  103. // create socket for listening to incoming connections
  104. tld->listenerHandle = socket(PF_INET, SOCK_STREAM, 0);
  105. if (tld->listenerHandle < 0) {
  106. perror("ERROR opening socket");
  107. retval = UA_ERROR;
  108. } else {
  109. // set port number, options and bind
  110. memset((void *) &serv_addr, sizeof(serv_addr),1);
  111. serv_addr.sin_family = AF_INET;
  112. serv_addr.sin_addr.s_addr = INADDR_ANY;
  113. serv_addr.sin_port = htons(port);
  114. if (setsockopt(tld->listenerHandle, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval)
  115. == -1) {
  116. perror("setsockopt");
  117. retval = UA_ERROR;
  118. } else {
  119. // bind to port
  120. if (bind(tld->listenerHandle, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
  121. perror("ERROR on binding");
  122. retval = UA_ERROR;
  123. } else {
  124. // TODO: implement
  125. // UA_String_sprintf("opc.tpc://localhost:%d", &(tld->endpointUrl), port);
  126. UA_String_copycstring("opc.tpc://localhost:16664/", &(tld->endpointUrl));
  127. }
  128. }
  129. }
  130. // finally
  131. if (retval == UA_SUCCESS) {
  132. // TODO: handle retval of pthread_create
  133. pthread_create( &tld->listenerThreadHandle, NULL, UA_TL_TCP_listen, (void*) tld);
  134. }
  135. return retval;
  136. }
  137. /** checks arguments and dispatches to worker or refuses to init */
  138. UA_Int32 UA_TL_init(UA_TL_Description* tlDesc, UA_Int32 port) {
  139. UA_Int32 retval = UA_SUCCESS;
  140. if (tlDesc->connectionType == UA_TL_CONNECTIONTYPE_TCPV4 && tlDesc->encoding == UA_TL_ENCODING_BINARY) {
  141. theTL.tld = tlDesc;
  142. UA_list_init(&theTL.connections);
  143. retval |= UA_TL_TCP_init(&theTL,port);
  144. } else {
  145. retval = UA_ERR_NOT_IMPLEMENTED;
  146. }
  147. return retval;
  148. }
  149. /** checks arguments and dispatches to worker or refuses to init */
  150. UA_Int32 UA_Stack_init(UA_TL_Description* tlDesc, UA_Int32 port) {
  151. UA_Int32 retval = UA_SUCCESS;
  152. retval = UA_TL_init(tlDesc,port);
  153. return retval;
  154. }