opcuaServerMini.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. /**************************************************************
  6. * opcuaServerMini is a pathologically unstructured bare bone
  7. * implementation of the 62541 communications w/o any structures
  8. * or comfort. Furthermore, the implementation assumes a
  9. * little endian target and consequently ignores all the rules
  10. * of 62541 towards security.
  11. *
  12. * The nice thing about this approach is that you can easily see
  13. * that the memory footprint of a simple server can be held
  14. * quite small and memory allocation capabilities is not needed
  15. * as long as features are consequently minimized.
  16. ****************************************************************/
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <memory.h>
  20. #include <errno.h> // errno, EINTR
  21. #include "ua_statuscodes.h"
  22. #include "ua_transport.h"
  23. #include "ua_transport_binary.h"
  24. #include "networklayer.h"
  25. #ifdef LINUX
  26. #include <sys/types.h>
  27. #include <sys/socket.h>
  28. #include <netinet/in.h>
  29. #include <sys/socketvar.h>
  30. #include <unistd.h>
  31. void server_run();
  32. #endif
  33. #define PORT 16664
  34. #define MAXMSG 512
  35. #define BUFFER_SIZE 8192
  36. int main(void) {
  37. #ifdef LINUX
  38. printf("Starting open62541 demo server on port %d\n", PORT);
  39. server_run();
  40. #endif
  41. return EXIT_SUCCESS;
  42. }
  43. #ifdef LINUX
  44. UA_Byte ack_msg_buf[] = { 0x41, 0x43, /* AC */
  45. 0x4b, 0x46, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, /* KF...... */
  46. 0xff, 0xff, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, /* ... ... */
  47. 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, /* ...@.... */
  48. 0x00, 0x00 /* .. */
  49. };
  50. UA_ByteString ack_msg = { sizeof(ack_msg_buf), ack_msg_buf };
  51. UA_ByteString* ack_msg_gb[] = { &ack_msg };
  52. UA_Byte opn_msg_buf[] = { 0x4f, 0x50, /* OP */
  53. 0x4e, 0x46, 0x88, 0x00, 0x00, 0x00, 0x19, 0x00, /* NF...... */
  54. 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x68, 0x74, /* ../...ht */
  55. 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x70, 0x63, /* tp://opc */
  56. 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, /* foundati */
  57. 0x6f, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x55, /* on.org/U */
  58. 0x41, 0x2f, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, /* A/Securi */
  59. 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, /* tyPolicy */
  60. 0x23, 0x4e, 0x6f, 0x6e, 0x65, 0xff, 0xff, 0xff, /* #None... */
  61. 0xff, 0xff, 0xff, 0xff, 0xff, 0x33, 0x00, 0x00, /* .....3.. */
  62. 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc1, /* ........ */
  63. 0x01, 0x10, 0x56, 0x73, 0x9e, 0xdf, 0x63, 0xcf, /* ..Vs..c. */
  64. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
  65. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
  66. 0x00, 0xff, 0xff, 0xff, 0xff, 0x19, 0x00, 0x00, /* ........ */
  67. 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
  68. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
  69. 0x00, 0x01, 0x00, 0x00, 0x00, 0x48 /* .....H */
  70. };
  71. UA_ByteString opn_msg = { sizeof(opn_msg_buf), opn_msg_buf };
  72. UA_ByteString* opn_msg_gb[] = { &opn_msg };
  73. UA_Byte scm_msg_buf[] = { 0x4d, 0x53, /* MS */
  74. 0x47, 0x46, 0x8b, 0x01, 0x00, 0x00, 0x19, 0x00, /* GF<XX>.. */ // <XX> = msglen. TODO: should be set or checked by writer?
  75. 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, /* ......4. */
  76. 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 /* ...... */
  77. };
  78. UA_Byte rsp_msg_buf[] = { 0x01, 0x00, /* ........ */
  79. 0xaf, 0x01, 0x2c, 0xc1, 0x73, 0x9e, 0xdf, 0x63, /* <><XXXXX */ // <> = response nS0-ID
  80. 0xcf, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* X>....<A */ // <X> = timestamp,
  81. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* A>...... */ // <A> = statuscode
  82. 0x00, 0x00 /* .. */
  83. };
  84. UA_Byte gep_msg_buf[] = {
  85. 0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, /* ...... */
  86. 0x00, 0x00, 0x6f, 0x70, 0x63, 0x2e, 0x74, 0x63, /* ..opc.tc */
  87. 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x30, 0x2e, 0x30, /* p://10.0 */
  88. 0x2e, 0x35, 0x33, 0x2e, 0x31, 0x39, 0x38, 0x3a, /* .53.198: */
  89. 0x31, 0x36, 0x36, 0x36, 0x34, 0x27, 0x00, 0x00, /* 16664'.. */
  90. 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, /* .http:// */
  91. 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x32, 0x35, 0x34, /* open6254 */
  92. 0x31, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x61, /* 1.info/a */
  93. 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, /* pplicati */
  94. 0x6f, 0x6e, 0x73, 0x2f, 0x34, 0x37, 0x31, 0x31, /* ons/4711 */
  95. 0x25, 0x00, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, /* %...http */
  96. 0x3a, 0x2f, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x36, /* ://open6 */
  97. 0x32, 0x35, 0x34, 0x31, 0x2e, 0x69, 0x6e, 0x66, /* 2541.inf */
  98. 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, /* o/produc */
  99. 0x74, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, /* t/releas */
  100. 0x65, 0x03, 0x02, 0x00, 0x00, 0x00, 0x45, 0x4e, /* e.....EN */
  101. 0x19, 0x00, 0x00, 0x00, 0x54, 0x68, 0x65, 0x20, /* ....The */
  102. 0x6f, 0x70, 0x65, 0x6e, 0x36, 0x32, 0x35, 0x34, /* open6254 */
  103. 0x31, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, /* 1 applic */
  104. 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, /* ation... */
  105. 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* ........ */
  106. 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, /* ........ */
  107. 0xff, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, /* ...../.. */
  108. 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, /* .http:// */
  109. 0x6f, 0x70, 0x63, 0x66, 0x6f, 0x75, 0x6e, 0x64, /* opcfound */
  110. 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6f, 0x72, /* ation.or */
  111. 0x67, 0x2f, 0x55, 0x41, 0x2f, 0x53, 0x65, 0x63, /* g/UA/Sec */
  112. 0x75, 0x72, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, /* urityPol */
  113. 0x69, 0x63, 0x79, 0x23, 0x4e, 0x6f, 0x6e, 0x65, /* icy#None */
  114. 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, /* ........ */
  115. 0x6d, 0x79, 0x2d, 0x61, 0x6e, 0x6f, 0x6e, 0x79, /* my-anony */
  116. 0x6d, 0x6f, 0x75, 0x73, 0x2d, 0x70, 0x6f, 0x6c, /* mous-pol */
  117. 0x69, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0xff, /* icy..... */
  118. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* ........ */
  119. 0xff, 0xff, 0xff, 0x41, 0x00, 0x00, 0x00, 0x68, /* ...A...h */
  120. 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x70, /* ttp://op */
  121. 0x63, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, /* cfoundat */
  122. 0x69, 0x6f, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, /* ion.org/ */
  123. 0x55, 0x41, 0x2d, 0x50, 0x72, 0x6f, 0x66, 0x69, /* UA-Profi */
  124. 0x6c, 0x65, 0x2f, 0x54, 0x72, 0x61, 0x6e, 0x73, /* le/Trans */
  125. 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x61, 0x74, /* port/uat */
  126. 0x63, 0x70, 0x2d, 0x75, 0x61, 0x73, 0x63, 0x2d, /* cp-uasc- */
  127. 0x75, 0x61, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, /* uabinary */
  128. 0x00 /* . */
  129. };
  130. UA_Byte csr_msg_buf[] = {
  131. 0x01, 0x01, 0x9a, 0x02, 0x00, 0x00, /* <XX>.. */ // <X> = sessionID
  132. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
  133. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* ........ */
  134. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
  135. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* ........ */
  136. 0x00, 0x00, 0x00, 0x00 /* .... */
  137. };
  138. UA_Byte asr_msg_buf[] = {
  139. 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, /* ...... */
  140. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* ...... */
  141. };
  142. UA_ByteString scm_msg = { sizeof(scm_msg_buf), scm_msg_buf };
  143. UA_ByteString rsp_msg = { sizeof(rsp_msg_buf), rsp_msg_buf };
  144. UA_ByteString* sf_msg_gb[] = { &scm_msg, &rsp_msg }; // servicefault
  145. UA_ByteString gep_msg = { sizeof(gep_msg_buf), gep_msg_buf };
  146. UA_ByteString* gep_msg_gb[] = { &scm_msg, &rsp_msg, &gep_msg }; //getendpoint response
  147. UA_ByteString csr_msg = { sizeof(csr_msg_buf), csr_msg_buf };
  148. UA_ByteString* csr_msg_gb[] = { &scm_msg, &rsp_msg, &csr_msg }; // create session response
  149. UA_ByteString asr_msg = { sizeof(asr_msg_buf), asr_msg_buf };
  150. UA_ByteString* asr_msg_gb[] = { &scm_msg, &rsp_msg, &asr_msg }; // activate session response
  151. UA_Int32 myProcess(TL_Connection* connection, const UA_ByteString* msg) {
  152. switch (*((UA_Int32*) &(msg->data[0]))) { // compare first four bytes
  153. case 0x464c4548: // HELF
  154. connection->writerCallback(connection, (const UA_ByteString**) &ack_msg_gb, 1);
  155. break;
  156. case 0x464e504f: // OPNF
  157. connection->writerCallback(connection, (const UA_ByteString**) &opn_msg_gb, 1);
  158. break;
  159. case 0x464f4c43: // CLOF
  160. connection->connectionState = CONNECTIONSTATE_CLOSE;
  161. break;
  162. case 0x4647534d: // MSGF
  163. switch (*((UA_Int16*) &(msg->data[26]))) {
  164. case 428: // GetEndpointsRequest
  165. #pragma GCC diagnostic push
  166. #pragma GCC diagnostic ignored "-Wstrict-aliasing"
  167. printf("server_run - GetEndpointsRequest\n");
  168. *(UA_Int32*) (&scm_msg_buf[4]) = sizeof(scm_msg_buf) + sizeof(rsp_msg_buf) + sizeof(gep_msg_buf);
  169. *(UA_Int16*) (&rsp_msg_buf[2]) = *(UA_Int16*) (&msg->data[26]) + 3;
  170. *(UA_Int32*) (&rsp_msg_buf[16]) = UA_STATUSCODE_GOOD;
  171. connection->writerCallback(connection, (const UA_ByteString**) &gep_msg_gb, 3);
  172. break;
  173. case 461: // CreateSessionRequest
  174. printf("server_run - CreateSessionRequest\n");
  175. *(UA_Int32*) (&scm_msg_buf[4]) = sizeof(scm_msg_buf) + sizeof(rsp_msg_buf) + sizeof(csr_msg_buf);
  176. *(UA_Int16*) (&rsp_msg_buf[2]) = *(UA_Int16*) (&msg->data[26]) + 3;
  177. *(UA_Int32*) (&rsp_msg_buf[16]) = UA_STATUSCODE_GOOD;
  178. connection->writerCallback(connection, (const UA_ByteString**) &csr_msg_gb, 3);
  179. break;
  180. case 467: // FIXME: ActivateSessionRequest
  181. printf("server_run - ActivateSessionRequest\n");
  182. *(UA_Int32*) (&scm_msg_buf[4]) = sizeof(scm_msg_buf) + sizeof(rsp_msg_buf) + sizeof(asr_msg_buf);
  183. *(UA_Int16*) (&rsp_msg_buf[2]) = *(UA_Int16*) (&msg->data[26]) + 3;
  184. *(UA_Int32*) (&rsp_msg_buf[16]) = UA_STATUSCODE_GOOD;
  185. connection->writerCallback(connection, (const UA_ByteString**) &asr_msg_gb, 3);
  186. break;
  187. default: // unknown service - send a simple response header of type UA_SERVICEFAULT
  188. *(UA_Int32*) (&scm_msg_buf[4]) = sizeof(scm_msg_buf) + sizeof(rsp_msg_buf);
  189. *(UA_Int16*) (&rsp_msg_buf[2]) = UA_SERVICEFAULT_NS0 + 2; // encodingBinary
  190. *(UA_Int32*) (&rsp_msg_buf[16]) = UA_STATUSCODE_BADNOTIMPLEMENTED;
  191. #pragma GCC diagnostic pop
  192. printf("server_run - unknown request %d\n", *((UA_Int16*) &(msg->data[26])));
  193. connection->writerCallback(connection, (const UA_ByteString**) &sf_msg_gb, 2);
  194. break;
  195. }
  196. break;
  197. }
  198. return UA_SUCCESS;
  199. }
  200. /** write message provided in the gather buffers to a tcp transport layer connection */
  201. UA_Int32 myWriter(struct TL_Connection const * c, UA_ByteString const * const * gather_buf, UA_UInt32 gather_len) {
  202. struct iovec iov[gather_len];
  203. UA_UInt32 total_len = 0;
  204. for(UA_UInt32 i=0;i<gather_len;i++) {
  205. iov[i].iov_base = gather_buf[i]->data;
  206. iov[i].iov_len = gather_buf[i]->length;
  207. total_len += gather_buf[i]->length;
  208. }
  209. struct msghdr message;
  210. message.msg_name = UA_NULL;
  211. message.msg_namelen = 0;
  212. message.msg_iov = iov;
  213. message.msg_iovlen = gather_len;
  214. message.msg_control = UA_NULL;
  215. message.msg_controllen = 0;
  216. message.msg_flags = 0;
  217. UA_UInt32 nWritten = 0;
  218. while (nWritten < total_len) {
  219. int n=0;
  220. do {
  221. DBG_VERBOSE(printf("myWriter - enter write with %d bytes to write\n",total_len));
  222. n = sendmsg(c->connectionHandle, &message, 0);
  223. DBG_VERBOSE(printf("myWriter - leave write with n=%d,errno={%d,%s}\n",n,(n>0)?0:errno,(n>0)?"":strerror(errno)));
  224. } while (n == -1L && errno == EINTR);
  225. if (n >= 0) {
  226. nWritten += n;
  227. break;
  228. // TODO: handle incompletely send messages
  229. } else {
  230. break;
  231. // TODO: error handling
  232. }
  233. }
  234. return UA_SUCCESS;
  235. }
  236. void server_run() {
  237. TL_Connection connection;
  238. connection.connectionState = CONNECTIONSTATE_CLOSED;
  239. connection.writerCallback = (TL_Writer) myWriter;
  240. connection.localConf.maxChunkCount = 1;
  241. connection.localConf.maxMessageSize = BUFFER_SIZE;
  242. connection.localConf.protocolVersion = 0;
  243. connection.localConf.recvBufferSize = BUFFER_SIZE;
  244. connection.localConf.recvBufferSize = BUFFER_SIZE;
  245. UA_ByteString slMessage = { -1, UA_NULL };
  246. int optval = 1;
  247. int sockfd, newsockfd, portno, clilen;
  248. char buffer[BUFFER_SIZE];
  249. struct sockaddr_in serv_addr, cli_addr;
  250. int n;
  251. /* First call to socket() function */
  252. sockfd = socket(PF_INET, SOCK_STREAM, 0);
  253. if (sockfd < 0) {
  254. perror("ERROR opening socket");
  255. exit(1);
  256. }
  257. /* Initialize socket structure */
  258. memset((void *) &serv_addr, 0, sizeof(serv_addr));
  259. portno = PORT;
  260. serv_addr.sin_family = AF_INET;
  261. serv_addr.sin_addr.s_addr = INADDR_ANY;
  262. serv_addr.sin_port = htons(portno);
  263. if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) == -1) {
  264. perror("setsockopt");
  265. exit(1);
  266. }
  267. /* Now bind the host address using bind() call.*/
  268. if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
  269. perror("ERROR on binding");
  270. exit(1);
  271. }
  272. /* Now start listening for the clients, here process will
  273. * go in sleep mode and will wait for the incoming connection
  274. */
  275. while (listen(sockfd, 5) != -1) {
  276. clilen = sizeof(cli_addr);
  277. /* Accept actual connection from the client */
  278. newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t*) &clilen);
  279. if (newsockfd < 0) {
  280. perror("ERROR on accept");
  281. exit(1);
  282. }
  283. printf("server_run - connection accepted: %i, state: %i\n", newsockfd, connection.connectionState);
  284. connection.connectionHandle = newsockfd;
  285. do {
  286. memset(buffer, 0, BUFFER_SIZE);
  287. n = read(newsockfd, buffer, BUFFER_SIZE);
  288. if (n > 0) {
  289. slMessage.data = (UA_Byte*) buffer;
  290. slMessage.length = n;
  291. DBG(printf("server_run - received=%d\n",n));
  292. myProcess(&connection, &slMessage);
  293. } else if (n <= 0) {
  294. perror("ERROR reading from socket1");
  295. connection.connectionState = CONNECTIONSTATE_CLOSE;
  296. }
  297. } while(connection.connectionState != CONNECTIONSTATE_CLOSE);
  298. shutdown(newsockfd,2);
  299. close(newsockfd);
  300. connection.connectionState = CONNECTIONSTATE_CLOSED;
  301. }
  302. shutdown(sockfd,2);
  303. close(sockfd);
  304. }
  305. #endif