finslib_connection.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. #if defined(_WIN32)
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #endif
  4. #include <ctype.h>
  5. #include <errno.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <time.h>
  10. #include <sys/stat.h>
  11. #include <sys/types.h>
  12. #if defined(_WIN32)
  13. #include <ws2tcpip.h>
  14. #else
  15. #include <unistd.h>
  16. #include <sys/socket.h>
  17. #include <netinet/in.h>
  18. #include <arpa/inet.h>
  19. #include <netdb.h>
  20. #endif
  21. #if defined(__FreeBSD__)
  22. #include <sys/timespec.h>
  23. #endif
  24. #include <signal.h>
  25. #include "fins.h"
  26. #include <ostream>
  27. #include <iostream>
  28. #define BUFLEN 1024
  29. #define SEND_TIMEOUT 10
  30. #define RECV_TIMEOUT 10
  31. #if defined(_WIN32)
  32. typedef const char send_tp;
  33. typedef const char sendto_tp;
  34. typedef const char setsockopt_tp;
  35. #else
  36. typedef void send_tp;
  37. typedef void sendto_tp;
  38. typedef void setsockopt_tp;
  39. #endif
  40. static int check_error_count(struct fins_sys_tp* sys, int error_code);
  41. static void init_system(struct fins_sys_tp* sys, int error_max);
  42. static struct fins_sys_tp* fins_close_socket(struct fins_sys_tp* sys);
  43. static struct fins_sys_tp* fins_close_socket_with_error(struct fins_sys_tp* sys, int* error_val);
  44. static int fins_recv_tcp_command(struct fins_sys_tp* sys, int total_len, struct fins_command_tp* command);
  45. static int fins_recv_tcp_header(struct fins_sys_tp* sys, int* error_val);
  46. static int fins_send_tcp_command(struct fins_sys_tp* sys, size_t bodylen, struct fins_command_tp* command);
  47. static int fins_send_tcp_header(struct fins_sys_tp* sys, size_t bodylen);
  48. static int fins_tcp_recv(struct fins_sys_tp* sys, unsigned char* buf, int len);
  49. static int tcp_errorcode_to_fins_retval(uint32_t errorcode);
  50. /*
  51. * static void init_system(struct fins_sys_tp *sys, int error_max);
  52. * 清除PLC结构以使其可用于新的连接。
  53. */
  54. static void init_system(struct fins_sys_tp* sys, int error_max)
  55. {
  56. time_t timeout_val;
  57. timeout_val = finslib_monotonic_sec_timer() - 2 * FINS_TIMEOUT;
  58. if (finslib_monotonic_sec_timer() > timeout_val) timeout_val = 0;
  59. sys->address[0] = 0;
  60. sys->port = FINS_DEFAULT_PORT;
  61. sys->sockfd = INVALID_SOCKET;
  62. sys->timeout = timeout_val;
  63. sys->plc_mode = FINS_MODE_UNKNOWN;
  64. sys->model[0] = 0;
  65. sys->version[0] = 0;
  66. sys->sid = 0;
  67. sys->comm_type = FINS_COMM_TYPE_UNKNOWN;
  68. sys->local_net = 0;
  69. sys->local_node = 0;
  70. sys->local_unit = 0;
  71. sys->remote_net = 0;
  72. sys->remote_node = 0;
  73. sys->remote_unit = 0;
  74. sys->error_count = 0;
  75. sys->error_max = error_max;
  76. sys->last_error = FINS_RETVAL_SUCCESS;
  77. sys->error_changed = false;
  78. } /* init_system */
  79. /*
  80. * 尝试通过FINS与远程FINS TCP服务器连接。 如果连接成功,
  81. * 则返回一个指向包含连接数据的系统结构的指针。 否则,返回值为NULL。
  82. * 简单模式
  83. * 传入FINS设备指针,远程设备IP,端口号,远程设备节点号,错误代码指针和最大错误数量(若错误数超过该值则会返回达到错误上限的错误)
  84. */
  85. struct fins_sys_tp* finslib_tcp_connect(struct fins_sys_tp* sys, const char* address, uint16_t port, uint8_t remote_node, int* error_val, int error_max)
  86. {
  87. return finslib_tcp_connect(sys, address, port, 0, 0, 0, 0, remote_node, 0, error_val, error_max);
  88. }
  89. /*
  90. * 尝试通过FINS与远程FINS TCP服务器连接。 如果连接成功,
  91. * 则返回一个指向包含连接数据的系统结构的指针。 否则,返回值为NULL。
  92. * 正常模式
  93. * 传入FINS设备指针,远程设备IP,端口号,本地网络号,本地节点号,本地单元号,远程设备网络号,远程设备节点号,远程设备单元号,错误代码指针和最大错误数(若错误数超过该值则会返回达到错误上限的错误)
  94. */
  95. struct fins_sys_tp* finslib_tcp_connect(struct fins_sys_tp* sys, const char* address, uint16_t port, uint8_t local_net,
  96. uint8_t local_node, uint8_t local_unit, uint8_t remote_net, uint8_t remote_node,
  97. uint8_t remote_unit, int* error_val, int error_max)
  98. {
  99. int sendlen;
  100. int recvlen;
  101. int retval;
  102. int keep_alive;
  103. int new_error;
  104. uint32_t command;
  105. uint32_t errorcode;
  106. struct sockaddr_in ws_addr;
  107. struct sockaddr_in cs_addr;
  108. struct timeval tv;
  109. unsigned char fins_tcp_header[FINS_MAX_TCP_HEADER];
  110. if (sys != NULL && finslib_monotonic_sec_timer() < sys->timeout + FINS_TIMEOUT && sys->timeout > 0)
  111. {
  112. if (error_val != NULL) *error_val = FINS_RETVAL_TRY_LATER;
  113. return sys;
  114. }
  115. if (sys == NULL)
  116. {
  117. if (port < FINS_PORT_RESERVED || port >= FINS_PORT_MAX) port = FINS_DEFAULT_PORT;
  118. if (address == NULL || address[0] == 0)
  119. {
  120. if (error_val != NULL) *error_val = FINS_RETVAL_NO_READ_ADDRESS;
  121. return NULL;
  122. }
  123. sys = new struct fins_sys_tp();
  124. if (sys == NULL)
  125. {
  126. if (error_val != NULL) *error_val = FINS_RETVAL_OUT_OF_MEMORY;
  127. return NULL;
  128. }
  129. init_system(sys, error_max);
  130. sys->comm_type = FINS_COMM_TYPE_TCP;
  131. sys->port = port;
  132. sys->local_net = local_net;
  133. sys->local_node = local_node;
  134. sys->local_unit = local_unit;
  135. sys->remote_net = remote_net;
  136. sys->remote_node = remote_node;
  137. sys->remote_unit = remote_unit;
  138. //snprintf(sys->address, 128, "%s", address);
  139. }
  140. #if defined(_WIN32)
  141. WSADATA Ws;
  142. if (WSAStartup(MAKEWORD(2, 2), &Ws) != 0)
  143. {
  144. return fins_close_socket_with_error(sys, error_val);
  145. }
  146. #endif
  147. sys->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  148. if (sys->sockfd == INVALID_SOCKET)
  149. {
  150. return fins_close_socket_with_error(sys, error_val);
  151. }
  152. keep_alive = true;
  153. if (setsockopt(sys->sockfd, SOL_SOCKET, SO_KEEPALIVE, (setsockopt_tp *)& keep_alive, sizeof(keep_alive)) < 0) return
  154. fins_close_socket_with_error(sys, error_val);
  155. tv.tv_sec = SEND_TIMEOUT;
  156. tv.tv_usec = 0;
  157. if (setsockopt(sys->sockfd, SOL_SOCKET, SO_SNDTIMEO, (setsockopt_tp *)& tv, sizeof(tv)) < 0) return
  158. fins_close_socket_with_error(sys, error_val);
  159. tv.tv_sec = RECV_TIMEOUT;
  160. tv.tv_usec = 0;
  161. if (setsockopt(sys->sockfd, SOL_SOCKET, SO_RCVTIMEO, (setsockopt_tp *)& tv, sizeof(tv)) < 0) return
  162. fins_close_socket_with_error(sys, error_val);
  163. memset(&ws_addr, 0, sizeof(ws_addr));
  164. ws_addr.sin_family = AF_INET;
  165. ws_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  166. ws_addr.sin_port = htons(0);
  167. if (bind(sys->sockfd, (struct sockaddr *)&ws_addr, sizeof(ws_addr)) < 0) return fins_close_socket_with_error(
  168. sys, error_val);
  169. memset(&cs_addr, 0, sizeof(cs_addr));
  170. cs_addr.sin_family = AF_INET;
  171. cs_addr.sin_port = htons(port);
  172. #if defined(_WIN32)
  173. //char转wchar
  174. const size_t cSize = strlen(address) + 1;
  175. wchar_t* addressWc = new wchar_t[cSize];
  176. mbstowcs(addressWc, address, cSize);
  177. retval = inet_pton(AF_INET, addressWc, &cs_addr.sin_addr.s_addr);
  178. #else
  179. retval = inet_pton(AF_INET, address, &cs_addr.sin_addr.s_addr);
  180. #endif
  181. if (retval < 0) return fins_close_socket_with_error(sys, error_val);
  182. else if (retval == 0)
  183. {
  184. sys->error_changed = (FINS_RETVAL_INVALID_IP_ADDRESS != sys->last_error);
  185. sys->last_error = FINS_RETVAL_INVALID_IP_ADDRESS;
  186. if (error_val != NULL) *error_val = sys->last_error;
  187. return fins_close_socket(sys);
  188. }
  189. if (connect(sys->sockfd, (struct sockaddr *)&cs_addr, sizeof(cs_addr)) < 0) return fins_close_socket_with_error(
  190. sys, error_val);
  191. /****************************************/
  192. /* */
  193. fins_tcp_header[0] = 'F'; /* Header */
  194. fins_tcp_header[1] = 'I'; /* */
  195. fins_tcp_header[2] = 'N'; /* */
  196. fins_tcp_header[3] = 'S'; /* */
  197. /* */
  198. fins_tcp_header[4] = 0x00; /* Length */
  199. fins_tcp_header[5] = 0x00; /* */
  200. fins_tcp_header[6] = 0x00; /* */
  201. fins_tcp_header[7] = 8 + 4; /* */
  202. /* */
  203. fins_tcp_header[8] = 0x00; /* Command */
  204. fins_tcp_header[9] = 0x00; /* */
  205. fins_tcp_header[10] = 0x00; /* */
  206. fins_tcp_header[11] = 0x00; /* */
  207. /* */
  208. fins_tcp_header[12] = 0x00; /* Error Code */
  209. fins_tcp_header[13] = 0x00; /* */
  210. fins_tcp_header[14] = 0x00; /* */
  211. fins_tcp_header[15] = 0x00; /* */
  212. /* */
  213. fins_tcp_header[16] = 0x00; /* Client node add */
  214. fins_tcp_header[17] = 0x00; /* */
  215. fins_tcp_header[18] = 0x00; /* */
  216. fins_tcp_header[19] = 0x00; /* Get node number automatically */
  217. /* */
  218. /****************************************/
  219. sendlen = 20;
  220. if (send(sys->sockfd, reinterpret_cast<char*>(fins_tcp_header), sendlen, 0) != sendlen)
  221. {
  222. sys->error_changed = (FINS_RETVAL_HEADER_SEND_ERROR != sys->last_error);
  223. sys->last_error = FINS_RETVAL_HEADER_SEND_ERROR;
  224. if (error_val != NULL) *error_val = sys->last_error;
  225. return fins_close_socket(sys);
  226. }
  227. sys->timeout = finslib_monotonic_sec_timer();
  228. recvlen = 24;
  229. if (fins_tcp_recv(sys, fins_tcp_header, recvlen) < recvlen)
  230. {
  231. sys->error_changed = (FINS_RETVAL_RESPONSE_HEADER_INCOMPLETE != sys->last_error);
  232. sys->last_error = FINS_RETVAL_RESPONSE_HEADER_INCOMPLETE;
  233. if (error_val != NULL) *error_val = sys->last_error;
  234. return fins_close_socket(sys);
  235. }
  236. command = fins_tcp_header[8];
  237. command <<= 8;
  238. command += fins_tcp_header[9];
  239. command <<= 8;
  240. command += fins_tcp_header[10];
  241. command <<= 8;
  242. command += fins_tcp_header[11];
  243. errorcode = fins_tcp_header[12];
  244. errorcode <<= 8;
  245. errorcode += fins_tcp_header[13];
  246. errorcode <<= 8;
  247. errorcode += fins_tcp_header[14];
  248. errorcode <<= 8;
  249. errorcode += fins_tcp_header[15];
  250. if (command != 0x00000001)
  251. {
  252. new_error = tcp_errorcode_to_fins_retval(errorcode);
  253. sys->error_changed = (new_error != sys->last_error);
  254. sys->last_error = new_error;
  255. if (error_val != NULL) *error_val = sys->last_error;
  256. return fins_close_socket(sys);
  257. }
  258. sys->local_node = fins_tcp_header[19];
  259. sys->remote_node = fins_tcp_header[23];
  260. sys->error_changed = (FINS_RETVAL_SUCCESS != sys->last_error);
  261. sys->last_error = FINS_RETVAL_SUCCESS;
  262. fins_cpudata_tp* cpudata = new fins_cpudata_tp();
  263. int error_code = finslib_cpu_unit_data_read(sys, cpudata);
  264. if (error_val != NULL) *error_val = sys->last_error;
  265. return sys;
  266. } /* finslib_tcp_connect */
  267. /*
  268. * finslib_disconnect(struct fins_sys_tp *sys);
  269. * 断开FINS客户端连接并释放与之关联的内存。
  270. */
  271. void finslib_disconnect(struct fins_sys_tp* sys)
  272. {
  273. if (sys == NULL) return;
  274. fins_close_socket(sys);
  275. free(sys);
  276. } /* finslib_disconnect */
  277. /*
  278. * static fins_sys_tp *fins_close_socket_with_error( fins_sys_tp *sys, int *error_val );
  279. *
  280. * 关闭FINS套接字并根据前一个操作返回的错误设置一个错误值。
  281. * 传入参数为FINS设备指针,错误代码指针
  282. */
  283. static struct fins_sys_tp* fins_close_socket_with_error(struct fins_sys_tp* sys, int* error_val)
  284. {
  285. int error_code;
  286. #if defined(_WIN32)
  287. error_code = XX_finslib_wsa_errorcode_to_fins_retval(WSAGetLastError());
  288. #else
  289. error_code = FINS_RETVAL_ERRNO_BASE + errno;
  290. #endif
  291. sys->error_changed = (error_code != sys->last_error);
  292. sys->last_error = error_code;
  293. if (error_val != NULL) *error_val = error_code;
  294. return fins_close_socket(sys);
  295. } /* fins_close_socket_with_error */
  296. /*
  297. * static fins_sys_tp *fins_close_socket( fins_sys_tp *sys );
  298. *
  299. * 关闭客户端TCP连接的FINS套接字。
  300. * 它首先将读取和发送的超时设置为零,否则停止套接字可能需要无限期的时间。
  301. * 它还重置错误计数器和重试的全局超时值。 指针返回一个指向系统结构的指针,或者在发生错误时返回NULL。
  302. */
  303. static struct fins_sys_tp* fins_close_socket(struct fins_sys_tp* sys)
  304. {
  305. struct timeval tv;
  306. struct linger li;
  307. if (sys == NULL) return NULL;
  308. if (sys->sockfd != INVALID_SOCKET)
  309. {
  310. if (sys->comm_type == FINS_COMM_TYPE_TCP)
  311. {
  312. li.l_onoff = false;
  313. li.l_linger = 0;
  314. setsockopt(sys->sockfd, SOL_SOCKET, SO_LINGER, (setsockopt_tp *)& li, sizeof(li));
  315. tv.tv_sec = 0;
  316. tv.tv_usec = 0;
  317. setsockopt(sys->sockfd, SOL_SOCKET, SO_SNDTIMEO, (setsockopt_tp *)& tv, sizeof(tv));
  318. tv.tv_sec = 0;
  319. tv.tv_usec = 0;
  320. setsockopt(sys->sockfd, SOL_SOCKET, SO_RCVTIMEO, (setsockopt_tp *)& tv, sizeof(tv));
  321. }
  322. closesocket(sys->sockfd);
  323. }
  324. sys->error_count = 0;
  325. sys->sockfd = INVALID_SOCKET;
  326. sys->timeout = finslib_monotonic_sec_timer();
  327. return sys;
  328. } /* fins_close_socket */
  329. /*
  330. * static int fins_tcp_recv( int index, uint8_t *buf, size_t len );
  331. *
  332. * 远程连接的PLC接收信息,该信息通过网络以FINS协议发送。
  333. * 只要有新的信息进入,数据就会附加到缓冲区并继续接收数据。
  334. */
  335. static int fins_tcp_recv(struct fins_sys_tp* sys, unsigned char* buf, int len)
  336. {
  337. int total_len;
  338. int recv_len;
  339. if (len <= 0) return 0;
  340. total_len = 0;
  341. for (;;)
  342. {
  343. recv_len = recv(sys->sockfd, reinterpret_cast<char*>(buf), len, 0);
  344. if (recv_len > 0)
  345. {
  346. len -= recv_len;
  347. buf += recv_len;
  348. total_len += recv_len;
  349. if (len <= 0) break;
  350. }
  351. else if (recv_len < 0)
  352. {
  353. if (errno == EAGAIN)
  354. {
  355. finslib_milli_second_sleep(10);
  356. continue;
  357. }
  358. }
  359. else return total_len;
  360. }
  361. return total_len;
  362. } /* fins_tcp_recv */
  363. /*
  364. * static int fins_send_tcp_header( fins_sys_tp *sys, size_t bodylen );
  365. *
  366. * 发送一个标准的FINS TCP头并等待完成。
  367. */
  368. static int fins_send_tcp_header(struct fins_sys_tp* sys, size_t bodylen)
  369. {
  370. int sendlen;
  371. unsigned char fins_tcp_header[FINS_MAX_TCP_HEADER];
  372. if (sys == NULL) return FINS_RETVAL_NOT_INITIALIZED;
  373. if (sys->sockfd == INVALID_SOCKET) return FINS_RETVAL_NOT_CONNECTED;
  374. if (bodylen > FINS_BODY_LEN) return FINS_RETVAL_BODY_TOO_LONG;
  375. bodylen += 8 + FINS_HEADER_LEN;
  376. fins_tcp_header[0] = 'F';
  377. fins_tcp_header[1] = 'I';
  378. fins_tcp_header[2] = 'N';
  379. fins_tcp_header[3] = 'S';
  380. fins_tcp_header[4] = (bodylen >> 24) & 0xff;
  381. fins_tcp_header[5] = (bodylen >> 16) & 0xff;
  382. fins_tcp_header[6] = (bodylen >> 8) & 0xff;
  383. fins_tcp_header[7] = (bodylen) & 0xff;
  384. fins_tcp_header[8] = 0x00;
  385. fins_tcp_header[9] = 0x00;
  386. fins_tcp_header[10] = 0x00;
  387. fins_tcp_header[11] = 0x02;
  388. fins_tcp_header[12] = 0x00;
  389. fins_tcp_header[13] = 0x00;
  390. fins_tcp_header[14] = 0x00;
  391. fins_tcp_header[15] = 0x00;
  392. sendlen = 16;
  393. if (send(sys->sockfd, reinterpret_cast<char*>(fins_tcp_header), sendlen, 0) != sendlen) return
  394. FINS_RETVAL_HEADER_SEND_ERROR;
  395. return FINS_RETVAL_SUCCESS;
  396. } /* fins_send_tcp_header */
  397. /*
  398. * static int check_error_count( struct fins_sys_tp *sys, int error_code );
  399. *
  400. * 检查连接上的错误代码和当前错误计数。
  401. * 如果错误代码指示成功,则计数器复位为0。
  402. * 否则,如果计数器达到最大错误计数,则计数器复位并且连接关闭。
  403. * 在这种情况下,函数返回最大错误计数错误。
  404. * 否则,错误表示为FINS_RETVAL参数。
  405. */
  406. static int check_error_count(struct fins_sys_tp* sys, int error_code)
  407. {
  408. if (sys == NULL) return FINS_RETVAL_NOT_INITIALIZED;
  409. if (sys->sockfd == INVALID_SOCKET ||
  410. sys->error_max < 0 ||
  411. error_code == FINS_RETVAL_SUCCESS ||
  412. error_code == FINS_RETVAL_SUCCESS_LAST_DATA)
  413. {
  414. sys->error_count = 0;
  415. sys->error_changed = (error_code != sys->last_error);
  416. sys->last_error = error_code;
  417. return error_code;
  418. }
  419. sys->error_count++;
  420. if (sys->error_count > sys->error_max) error_code = FINS_RETVAL_MAX_ERROR_COUNT;
  421. switch (error_code)
  422. {
  423. case FINS_RETVAL_MAX_ERROR_COUNT:
  424. case FINS_RETVAL_CLOSED_BY_REMOTE:
  425. case FINS_RETVAL_WSA_UNRECOGNIZED_ERROR:
  426. case FINS_RETVAL_WSA_NOT_INITIALIZED:
  427. case FINS_RETVAL_WSA_SYS_NOT_READY:
  428. case FINS_RETVAL_WSA_VER_NOT_SUPPORTED:
  429. case FINS_RETVAL_WSA_E_ACCES:
  430. case FINS_RETVAL_WSA_E_ADDR_IN_USE:
  431. case FINS_RETVAL_WSA_E_ADDR_NOT_AVAIL:
  432. case FINS_RETVAL_WSA_E_AF_NO_SUPPORT:
  433. case FINS_RETVAL_WSA_E_CONN_REFUSED:
  434. case FINS_RETVAL_WSA_E_HOST_UNREACH:
  435. case FINS_RETVAL_WSA_E_MFILE:
  436. case FINS_RETVAL_WSA_E_NET_DOWN:
  437. case FINS_RETVAL_WSA_E_NET_RESET:
  438. case FINS_RETVAL_WSA_E_NET_UNREACH:
  439. case FINS_RETVAL_WSA_E_NO_PROTO_OPT:
  440. case FINS_RETVAL_WSA_E_NOT_CONN:
  441. case FINS_RETVAL_WSA_E_NOT_SOCK:
  442. case FINS_RETVAL_WSA_E_PROC_LIM:
  443. case FINS_RETVAL_WSA_E_PROTO_NO_SUPPORT:
  444. case FINS_RETVAL_WSA_E_PROTO_TYPE:
  445. case FINS_RETVAL_WSA_E_PROVIDER_FAILED_INIT:
  446. case FINS_RETVAL_WSA_E_SOCKT_NO_SUPPORT:
  447. sys->error_count = 0;
  448. sys->error_changed = (error_code != sys->last_error);
  449. sys->last_error = error_code;
  450. fins_close_socket(sys);
  451. break;
  452. }
  453. return error_code;
  454. } /* check_error_count */
  455. /*
  456. * static int fins_send_tcp_command( fins_sys_tp *sys, size_t bodylen, fins_command_tp *command );
  457. *
  458. *通过TCP连接将命令头和主体发送到远程PLC。 TCP头应该已经发送过。
  459. */
  460. static int fins_send_tcp_command(struct fins_sys_tp* sys, size_t bodylen, struct fins_command_tp* command)
  461. {
  462. int sendlen;
  463. int retval;
  464. if (sys == NULL) return FINS_RETVAL_NOT_INITIALIZED;
  465. if (command == NULL) return FINS_RETVAL_NO_COMMAND;
  466. if (sys->sockfd == INVALID_SOCKET) return FINS_RETVAL_NOT_CONNECTED;
  467. if (bodylen > FINS_BODY_LEN) return FINS_RETVAL_BODY_TOO_LONG;
  468. sendlen = FINS_HEADER_LEN + (int)bodylen;
  469. retval = send(sys->sockfd, (send_tp *)command, sendlen, 0);
  470. if (retval < 0) return FINS_RETVAL_ERRNO_BASE + errno;
  471. if (retval != sendlen) return FINS_RETVAL_COMMAND_SEND_ERROR;
  472. return FINS_RETVAL_SUCCESS;
  473. } /* fins_send_tcp_command */
  474. /*
  475. * static int tcp_errorcode_to_fins_retval( uint32_t errorcode );
  476. *
  477. * 将FINS / TCP头部错误代码转换为FINS_RETVAL,FINS_RETVAL被调用例程识别。
  478. */
  479. static int tcp_errorcode_to_fins_retval(uint32_t errorcode)
  480. {
  481. switch (errorcode)
  482. {
  483. case 0x00000000: return FINS_RETVAL_CLOSED_BY_REMOTE;
  484. case 0x00000001: return FINS_RETVAL_NO_FINS_HEADER;
  485. case 0x00000002: return FINS_RETVAL_DATA_LENGTH_TOO_LONG;
  486. case 0x00000003: return FINS_RETVAL_COMMAND_NOT_SUPPORTED;
  487. case 0x00000020: return FINS_RETVAL_ALL_CONNECTIONS_IN_USE;
  488. case 0x00000021: return FINS_RETVAL_NODE_ALREADY_CONNECTED;
  489. case 0x00000022: return FINS_RETVAL_NODE_IP_PROTECTED;
  490. case 0x00000023: return FINS_RETVAL_CLIENT_NODE_OUT_OF_RANGE;
  491. case 0x00000024: return FINS_RETVAL_SAME_NODE_ADDRESS;
  492. case 0x00000025: return FINS_RETVAL_NO_NODE_ADDRESS_AVAILABLE;
  493. }
  494. return FINS_RETVAL_ILLEGAL_FINS_COMMAND;
  495. } /* tcp_errorcode_to_fins_retval */
  496. /*
  497. * int fins_recv_tcp_header( fins_sys_tp *sys, int *error_val );
  498. *
  499. * 从远程PLC接收TCP响应头。 该函数检查返回的标题的完整性。
  500. * 如果发生错误,则返回-1。 否则,返回值是以下有效负载的大小。
  501. * 请注意,在某些情况下,有效负载长度可能为0,这不是错误。
  502. */
  503. static int fins_recv_tcp_header(struct fins_sys_tp* sys, int* error_val)
  504. {
  505. int recvlen;
  506. int retval;
  507. uint32_t command;
  508. uint32_t errorcode;
  509. unsigned char fins_tcp_header[FINS_MAX_TCP_HEADER];
  510. if (sys == NULL || sys->sockfd == INVALID_SOCKET) return -1;
  511. recvlen = 16;
  512. retval = fins_tcp_recv(sys, fins_tcp_header, recvlen);
  513. if (retval < recvlen)
  514. {
  515. if (error_val != NULL) *error_val = FINS_RETVAL_RESPONSE_HEADER_INCOMPLETE;
  516. return -1;
  517. }
  518. command = fins_tcp_header[8];
  519. command <<= 8;
  520. command += fins_tcp_header[9];
  521. command <<= 8;
  522. command += fins_tcp_header[10];
  523. command <<= 8;
  524. command += fins_tcp_header[11];
  525. errorcode = fins_tcp_header[12];
  526. errorcode <<= 8;
  527. errorcode += fins_tcp_header[13];
  528. errorcode <<= 8;
  529. errorcode += fins_tcp_header[14];
  530. errorcode <<= 8;
  531. errorcode += fins_tcp_header[15];
  532. if (command != 0x00000002)
  533. {
  534. if (error_val != NULL) *error_val = tcp_errorcode_to_fins_retval(errorcode);
  535. return -1;
  536. }
  537. recvlen = fins_tcp_header[6];
  538. recvlen <<= 8;
  539. recvlen += fins_tcp_header[7];
  540. recvlen -= 8;
  541. if (recvlen > FINS_HEADER_LEN + FINS_BODY_LEN)
  542. {
  543. if (error_val != NULL) *error_val = FINS_RETVAL_BODY_TOO_LONG;
  544. return -1;
  545. }
  546. if (error_val != NULL) *error_val = FINS_RETVAL_SUCCESS;
  547. return recvlen;
  548. } /* fins_recv_tcp_header */
  549. /*
  550. * static int fins_recv_tcp_command( fins_sys_tp *sys, int total_len, fins_command_tp *command );
  551. *
  552. * 从远程PLC接收命令结构。 字节数长度作为参数提供。 这个长度包括完整的头和一些正文。
  553. */
  554. static int fins_recv_tcp_command(struct fins_sys_tp* sys, int total_len, struct fins_command_tp* command)
  555. {
  556. if (fins_tcp_recv(sys, (unsigned char *)command, total_len) != total_len) return FINS_RETVAL_RESPONSE_INCOMPLETE;
  557. return FINS_RETVAL_SUCCESS;
  558. } /* fins_recv_tcp_command */
  559. /*
  560. * int XX_finslib_communicate( fins_sys_tp *sys, fins_command_tp *command, size_t *bodylen );
  561. *
  562. * 外部程序用于执行与FINS服务器的实际通信的功能。
  563. * 该功能既发送命令又接收响应并隐藏调用例程的低级通信的所有细节。
  564. * 该函数返回FINS_RETVAL _...列表中的成功或错误代码。
  565. */
  566. int XX_finslib_communicate(struct fins_sys_tp* sys, struct fins_command_tp* command, size_t* bodylen)
  567. {
  568. int a;
  569. int recvlen;
  570. int retval;
  571. int error_val;
  572. uint16_t endcode;
  573. unsigned char sent_header[FINS_HEADER_LEN];
  574. unsigned char waste_buffer[BUFLEN];
  575. if (sys == NULL) return check_error_count(sys, FINS_RETVAL_NOT_INITIALIZED);
  576. if (command == NULL) return check_error_count(sys, FINS_RETVAL_NO_COMMAND);
  577. if (bodylen == NULL) return check_error_count(sys, FINS_RETVAL_NO_COMMAND_LENGTH);
  578. if (sys->sockfd == INVALID_SOCKET) return check_error_count(sys, FINS_RETVAL_NOT_CONNECTED);
  579. if (sys->comm_type == FINS_COMM_TYPE_TCP)
  580. {
  581. error_val = FINS_RETVAL_SUCCESS;
  582. for (a = 0; a < FINS_HEADER_LEN; a++) sent_header[a] = command->header[a];
  583. if ((retval = fins_send_tcp_header(sys, *bodylen)) != FINS_RETVAL_SUCCESS) return
  584. check_error_count(sys, retval);
  585. if ((retval = fins_send_tcp_command(sys, *bodylen, command)) != FINS_RETVAL_SUCCESS) return
  586. check_error_count(sys, retval);
  587. recvlen = fins_recv_tcp_header(sys, &error_val);
  588. if (recvlen < 0) return check_error_count(sys, error_val);
  589. if (recvlen == 0) return check_error_count(sys, FINS_RETVAL_BODY_TOO_SHORT);
  590. if ((retval = fins_recv_tcp_command(sys, recvlen, command)) != FINS_RETVAL_SUCCESS) return
  591. check_error_count(sys, retval);
  592. if (command->header[FINS_ICF] != (sent_header[FINS_ICF] | 0x40) ||
  593. command->header[FINS_RSV] != 0x00 ||
  594. command->header[FINS_DNA] != sent_header[FINS_SNA] ||
  595. command->header[FINS_DA1] != sent_header[FINS_SA1] ||
  596. command->header[FINS_DA2] != sent_header[FINS_SA2] ||
  597. command->header[FINS_SNA] != sent_header[FINS_DNA] ||
  598. command->header[FINS_SA1] != sent_header[FINS_DA1] ||
  599. command->header[FINS_SA2] != sent_header[FINS_DA2] ||
  600. command->header[FINS_SID] != sent_header[FINS_SID] ||
  601. command->header[FINS_MRC] != sent_header[FINS_MRC] ||
  602. command->header[FINS_SRC] != sent_header[FINS_SRC])
  603. {
  604. while (fins_tcp_recv(sys, waste_buffer, BUFLEN) > 0)
  605. {
  606. };
  607. return check_error_count(sys, FINS_RETVAL_SYNC_ERROR);
  608. }
  609. recvlen -= FINS_HEADER_LEN;
  610. *bodylen = recvlen;
  611. if (recvlen < 2) return check_error_count(sys, FINS_RETVAL_BODY_TOO_SHORT);
  612. endcode = command->body[0] & 0x7f;
  613. endcode <<= 8;
  614. endcode += command->body[1] & 0x3f;
  615. return check_error_count(sys, endcode);
  616. }
  617. return check_error_count(sys, FINS_RETVAL_NOT_INITIALIZED);
  618. } /* XX_finslib_communicate */
  619. /*
  620. * int XX_finslib_wsa_errorcode_to_fins_retval( int errorcode );
  621. * 将一个Windows WSA错误代码转换为FINS_RETVAL_值。
  622. */
  623. int XX_finslib_wsa_errorcode_to_fins_retval(int errorcode)
  624. {
  625. switch (errorcode)
  626. {
  627. #if defined(_WIN32)
  628. case WSASYSNOTREADY: return FINS_RETVAL_WSA_SYS_NOT_READY;
  629. case WSAVERNOTSUPPORTED: return FINS_RETVAL_WSA_VER_NOT_SUPPORTED;
  630. case WSANOTINITIALISED: return FINS_RETVAL_WSA_NOT_INITIALIZED;
  631. case WSAEACCES: return FINS_RETVAL_WSA_E_ACCES;
  632. case WSAEADDRINUSE: return FINS_RETVAL_WSA_E_ADDR_IN_USE;
  633. case WSAEADDRNOTAVAIL: return FINS_RETVAL_WSA_E_ADDR_NOT_AVAIL;
  634. case WSAEAFNOSUPPORT: return FINS_RETVAL_WSA_E_AF_NO_SUPPORT;
  635. case WSAEALREADY: return FINS_RETVAL_WSA_E_ALREADY;
  636. case WSAECONNREFUSED: return FINS_RETVAL_WSA_E_CONN_REFUSED;
  637. case WSAEFAULT: return FINS_RETVAL_WSA_E_FAULT;
  638. case WSAEHOSTUNREACH: return FINS_RETVAL_WSA_E_HOST_UNREACH;
  639. case WSAEINPROGRESS: return FINS_RETVAL_WSA_E_IN_PROGRESS;
  640. case WSAEINTR: return FINS_RETVAL_WSA_E_INTR;
  641. case WSAEINVAL: return FINS_RETVAL_WSA_E_INVAL;
  642. case WSAEINVALIDPROCTABLE: return FINS_RETVAL_WSA_E_INVALID_PROCTABLE;
  643. case WSAEINVALIDPROVIDER: return FINS_RETVAL_WSA_E_INVALID_PROVIDER;
  644. case WSAEISCONN: return FINS_RETVAL_WSA_E_IS_CONN;
  645. case WSAEMFILE: return FINS_RETVAL_WSA_E_MFILE;
  646. case WSAENETDOWN: return FINS_RETVAL_WSA_E_NET_DOWN;
  647. case WSAENETRESET: return FINS_RETVAL_WSA_E_NET_RESET;
  648. case WSAENETUNREACH: return FINS_RETVAL_WSA_E_NET_UNREACH;
  649. case WSAENOBUFS: return FINS_RETVAL_WSA_E_NOBUFS;
  650. case WSAENOPROTOOPT: return FINS_RETVAL_WSA_E_NO_PROTO_OPT;
  651. case WSAENOTCONN: return FINS_RETVAL_WSA_E_NOT_CONN;
  652. case WSAENOTSOCK: return FINS_RETVAL_WSA_E_NOT_SOCK;
  653. case WSAEPROCLIM: return FINS_RETVAL_WSA_E_PROC_LIM;
  654. case WSAEPROTONOSUPPORT: return FINS_RETVAL_WSA_E_PROTO_NO_SUPPORT;
  655. case WSAEPROTOTYPE: return FINS_RETVAL_WSA_E_PROTO_TYPE;
  656. case WSAEPROVIDERFAILEDINIT: return FINS_RETVAL_WSA_E_PROVIDER_FAILED_INIT;
  657. case WSAESOCKTNOSUPPORT: return FINS_RETVAL_WSA_E_SOCKT_NO_SUPPORT;
  658. case WSAETIMEDOUT: return FINS_RETVAL_WSA_E_TIMED_OUT;
  659. case WSAEWOULDBLOCK: return FINS_RETVAL_WSA_E_WOULD_BLOCK;
  660. #endif
  661. default: return FINS_RETVAL_WSA_UNRECOGNIZED_ERROR;
  662. }
  663. } /* XX_finslib_wsa_errorcode_to_fins_retval */