PageRenderTime 106ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/platform/FNET/fnet_stack/services/tftp/fnet_tftp_cln.c

https://gitlab.com/fuggles/ucos
C | 469 lines | 294 code | 76 blank | 99 comment | 62 complexity | 8861ab23d605d2395fcfff2e0c3be247 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
  1. /**************************************************************************
  2. *
  3. * Copyright 2011-2015 by Andrey Butok. FNET Community.
  4. * Copyright 2008-2010 by Andrey Butok. Freescale Semiconductor, Inc.
  5. *
  6. ***************************************************************************
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License Version 3
  9. * or later (the "LGPL").
  10. *
  11. * As a special exception, the copyright holders of the FNET project give you
  12. * permission to link the FNET sources with independent modules to produce an
  13. * executable, regardless of the license terms of these independent modules,
  14. * and to copy and distribute the resulting executable under terms of your
  15. * choice, provided that you also meet, for each linked independent module,
  16. * the terms and conditions of the license of that module.
  17. * An independent module is a module which is not derived from or based
  18. * on this library.
  19. * If you modify the FNET sources, you may extend this exception
  20. * to your version of the FNET sources, but you are not obligated
  21. * to do so. If you do not wish to do so, delete this
  22. * exception statement from your version.
  23. *
  24. * This program is distributed in the hope that it will be useful,
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  27. *
  28. * You should have received a copy of the GNU General Public License
  29. * and the GNU Lesser General Public License along with this program.
  30. * If not, see <http://www.gnu.org/licenses/>.
  31. *
  32. **********************************************************************/ /*!
  33. *
  34. * @file fnet_tftp_cln.c
  35. *
  36. * @author Andrey Butok
  37. *
  38. * @brief TFTP Client implementation.
  39. *
  40. ***************************************************************************/
  41. #include "fnet.h"
  42. #if FNET_CFG_TFTP_CLN
  43. #include "stack/fnet_netif_prv.h"
  44. #if FNET_CFG_DEBUG_TFTP_CLN
  45. #define FNET_DEBUG_TFTP FNET_DEBUG
  46. #else
  47. #define FNET_DEBUG_TFTP(...)
  48. #endif
  49. /************************************************************************
  50. * Definitions
  51. *************************************************************************/
  52. #define FNET_TFTP_MODE "octet"
  53. #define FNET_TFTP_MODE_SIZE_MAX (9)
  54. #define FNET_TFTP_FILENAME_SIZE_MAX (FNET_TFTP_DATA_SIZE_MAX-FNET_TFTP_MODE_SIZE_MAX)
  55. #define FNET_TFTP_OPCODE_READ_REQUEST (1)
  56. #define FNET_TFTP_OPCODE_WRITE_REQUEST (2)
  57. #define FNET_TFTP_OPCODE_DATA (3)
  58. #define FNET_TFTP_OPCODE_ACK (4)
  59. #define FNET_TFTP_OPCODE_ERROR (5)
  60. #define FNET_TFTP_ERR_PARAMS "ERROR: Wrong input parameters."
  61. #define FNET_TFTP_ERR_SOCKET_CREATION "ERROR: Socket creation error."
  62. #define FNET_TFTP_ERR_SOCKET_BIND "ERROR: Socket Error during bind."
  63. #define FNET_TFTP_ERR_SERVICE "ERROR: Service registration is failed."
  64. #define FNET_TFTP_ERR_IS_INITIALIZED "ERROR: TFTP is already initialized."
  65. static void fnet_tftp_cln_state_machine(void *fnet_tftp_cln_if_p);
  66. /* TFTP packets:*/
  67. FNET_COMP_PACKED_BEGIN
  68. struct fnet_tftp_packet_request
  69. {
  70. unsigned short opcode FNET_COMP_PACKED;
  71. unsigned char filename_mode[FNET_TFTP_DATA_SIZE_MAX] FNET_COMP_PACKED; /* Filename, Mode */
  72. };
  73. FNET_COMP_PACKED_END
  74. FNET_COMP_PACKED_BEGIN
  75. struct fnet_tftp_packet_data
  76. {
  77. unsigned short opcode FNET_COMP_PACKED;
  78. unsigned short block_number FNET_COMP_PACKED;
  79. unsigned char data[FNET_TFTP_DATA_SIZE_MAX] FNET_COMP_PACKED;
  80. };
  81. FNET_COMP_PACKED_END
  82. FNET_COMP_PACKED_BEGIN
  83. struct fnet_tftp_packet_ack
  84. {
  85. unsigned short opcode FNET_COMP_PACKED;
  86. unsigned short block_number FNET_COMP_PACKED;
  87. };
  88. FNET_COMP_PACKED_END
  89. FNET_COMP_PACKED_BEGIN
  90. struct fnet_tftp_packet_error
  91. {
  92. unsigned short opcode FNET_COMP_PACKED;
  93. unsigned short error_code FNET_COMP_PACKED;
  94. char error_message[FNET_TFTP_DATA_SIZE_MAX] FNET_COMP_PACKED;
  95. };
  96. FNET_COMP_PACKED_END
  97. #if 0 /* Actually it's not needed as a TFT server sends error string message with packet. */
  98. const static char *fnet_tftp_error[] =
  99. {
  100. "Not defined, see error message (if any).",
  101. "File not found.",
  102. "Access violation.",
  103. "Disk full or allocation exceeded.",
  104. "Illegal TFTP operation.",
  105. "Unknown transfer ID.",
  106. "File already exists.",
  107. "No such user."
  108. };
  109. #endif
  110. /* Default error message. */
  111. static char FNET_TFTP_DEFAULT_ERROR[] = "Connection failed";
  112. /************************************************************************
  113. * TFTP-client interface structure
  114. *************************************************************************/
  115. typedef struct
  116. {
  117. SOCKET socket_client;
  118. fnet_poll_desc_t service_descriptor;
  119. fnet_tftp_request_t request_type;
  120. fnet_tftp_cln_state_t state; /* Current state.*/
  121. struct sockaddr server_addr; /* TFTP Server address. */
  122. fnet_tftp_cln_handler_t handler; /* Callback function. */
  123. void *handler_param; /* Handler specific parameter. */
  124. unsigned short server_port; /* TFTP Server port number for data transfer. */
  125. unsigned short block_number_ack; /* Acknoladged block number. */
  126. unsigned long last_time; /* Last receive time, used for timeout detection. */
  127. unsigned long timeout; /* Timeout in ms. */
  128. union
  129. {
  130. struct fnet_tftp_packet_request packet_request;
  131. struct fnet_tftp_packet_data packet_data;
  132. struct fnet_tftp_packet_ack packet_ack;
  133. struct fnet_tftp_packet_error packet_error;
  134. };
  135. unsigned long packet_size;
  136. int tx_data_size;
  137. }
  138. fnet_tftp_if_t;
  139. /* TFTP-client interface */
  140. static fnet_tftp_if_t fnet_tftp_if;
  141. /************************************************************************
  142. * NAME: fnet_tftp_cln_init
  143. *
  144. * DESCRIPTION: TFTP-client initialization.
  145. ************************************************************************/
  146. int fnet_tftp_cln_init( struct fnet_tftp_cln_params *params )
  147. {
  148. struct sockaddr addr_client;
  149. unsigned char *data_ptr;
  150. /* Check input parameters. */
  151. if((params == 0) || (params->server_addr.sa_family == AF_UNSPEC) ||
  152. fnet_socket_addr_is_unspecified(&params->server_addr) ||
  153. (params->file_name == 0) || (params->handler == 0))
  154. {
  155. FNET_DEBUG_TFTP(FNET_TFTP_ERR_PARAMS);
  156. goto ERROR;
  157. }
  158. if(fnet_tftp_if.state != FNET_TFTP_CLN_STATE_DISABLED)
  159. {
  160. FNET_DEBUG_TFTP(FNET_TFTP_ERR_IS_INITIALIZED);
  161. goto ERROR;
  162. }
  163. /* Reset interface structure. */
  164. fnet_memset_zero(&fnet_tftp_if, sizeof(fnet_tftp_if_t));
  165. fnet_tftp_if.server_addr = params->server_addr;
  166. if(fnet_tftp_if.server_addr.sa_port == 0)
  167. fnet_tftp_if.server_addr.sa_port = FNET_CFG_TFTP_CLN_PORT; /* Default TFTP server port number.*/
  168. fnet_tftp_if.handler = params->handler;
  169. fnet_tftp_if.handler_param = params->handler_param;
  170. if(params->timeout == 0 )
  171. {
  172. fnet_tftp_if.timeout = FNET_CFG_TFTP_CLN_TIMEOUT*1000;
  173. }
  174. else
  175. {
  176. fnet_tftp_if.timeout = (unsigned long) params->timeout*1000;
  177. }
  178. /* Create client socket */
  179. if((fnet_tftp_if.socket_client = socket(params->server_addr.sa_family, SOCK_DGRAM, 0)) == SOCKET_INVALID)
  180. {
  181. FNET_DEBUG_TFTP(FNET_TFTP_ERR_SOCKET_CREATION);
  182. goto ERROR;
  183. }
  184. /* Bind socket (optional) */
  185. fnet_memset_zero(&addr_client, sizeof(addr_client));
  186. addr_client.sa_family = params->server_addr.sa_family;
  187. if ( bind( fnet_tftp_if.socket_client, (struct sockaddr*)&addr_client, sizeof(addr_client)) == SOCKET_ERROR )
  188. {
  189. FNET_DEBUG_TFTP(FNET_TFTP_ERR_SOCKET_BIND);
  190. goto ERROR_1;
  191. }
  192. fnet_tftp_if.request_type = params->request_type;
  193. /* Prepare request. */
  194. switch(fnet_tftp_if.request_type)
  195. {
  196. case FNET_TFTP_REQUEST_WRITE:
  197. fnet_tftp_if.packet_request.opcode = FNET_HTONS(FNET_TFTP_OPCODE_WRITE_REQUEST);
  198. break;
  199. case FNET_TFTP_REQUEST_READ:
  200. fnet_tftp_if.packet_request.opcode = FNET_HTONS(FNET_TFTP_OPCODE_READ_REQUEST);
  201. break;
  202. default:
  203. goto ERROR_1;
  204. }
  205. data_ptr = fnet_tftp_if.packet_request.filename_mode;
  206. fnet_strncpy( (char*)data_ptr, params->file_name, FNET_TFTP_FILENAME_SIZE_MAX);
  207. data_ptr += fnet_strlen(params->file_name)+1;
  208. fnet_strncpy((char*)data_ptr,FNET_TFTP_MODE, FNET_TFTP_MODE_SIZE_MAX);
  209. fnet_tftp_if.packet_size = sizeof(fnet_tftp_if.packet_request.opcode)+fnet_strlen(params->file_name)+1+sizeof(FNET_TFTP_MODE);
  210. /* Register TFTP service. */
  211. fnet_tftp_if.service_descriptor = fnet_poll_service_register(fnet_tftp_cln_state_machine, (void *) &fnet_tftp_if);
  212. if(fnet_tftp_if.service_descriptor == (fnet_poll_desc_t)FNET_ERR)
  213. {
  214. FNET_DEBUG_TFTP(FNET_TFTP_ERR_SERVICE);
  215. goto ERROR_1;
  216. }
  217. fnet_tftp_if.state = FNET_TFTP_CLN_STATE_SEND_REQUEST; /* => Send REQUEST */
  218. return FNET_OK;
  219. ERROR_1:
  220. closesocket(fnet_tftp_if.socket_client);
  221. ERROR:
  222. return FNET_ERR;
  223. }
  224. /************************************************************************
  225. * NAME: fnet_tftp_cln_state_machine
  226. *
  227. * DESCRIPTION: TFTP-client state machine.
  228. ************************************************************************/
  229. static void fnet_tftp_cln_state_machine( void *fnet_tftp_cln_if_p )
  230. {
  231. struct sockaddr addr;
  232. unsigned int addr_len;
  233. int sent_size;
  234. int received;
  235. fnet_tftp_if_t *tftp_if = (fnet_tftp_if_t *)fnet_tftp_cln_if_p;
  236. switch(tftp_if->state)
  237. {
  238. /*---- SEND_REQUEST --------------------------------------------*/
  239. case FNET_TFTP_CLN_STATE_SEND_REQUEST:
  240. addr = fnet_tftp_if.server_addr;
  241. /* ---- Send request ---- */
  242. sent_size = sendto(tftp_if->socket_client, (char*)&tftp_if->packet_request, (int)tftp_if->packet_size, 0,
  243. &addr, sizeof(addr));
  244. if (sent_size!=tftp_if->packet_size)
  245. {
  246. goto ERROR;
  247. }
  248. else
  249. {
  250. tftp_if->last_time = fnet_timer_ticks();
  251. tftp_if->state = FNET_TFTP_CLN_STATE_HANDLE_REQUEST;
  252. }
  253. break;
  254. /*---- HANDLE_REQUEST -----------------------------------------------*/
  255. case FNET_TFTP_CLN_STATE_HANDLE_REQUEST:
  256. /* Receive data */
  257. addr_len = sizeof(addr);
  258. received = recvfrom (tftp_if->socket_client, (char*)&tftp_if->packet_data, sizeof(struct fnet_tftp_packet_data), 0,
  259. &addr, &addr_len );
  260. if(received >= 4)
  261. {
  262. /* Is it for us. */
  263. if(!fnet_socket_addr_are_equal(&addr, &tftp_if->server_addr))
  264. {
  265. FNET_DEBUG_TFTP( "\nWARNING: Block not from our server!" );
  266. }
  267. /* Error. */
  268. else if ( tftp_if->packet_data.opcode == FNET_HTONS(FNET_TFTP_OPCODE_ERROR) )
  269. {
  270. tftp_if->handler(tftp_if->request_type, (unsigned char *)&tftp_if->packet_error.error_message[0], fnet_htons(tftp_if->packet_error.error_code), FNET_ERR, tftp_if->handler_param);
  271. tftp_if->state = FNET_TFTP_CLN_STATE_RELEASE;
  272. }
  273. /* Received Data. */
  274. else if( (tftp_if->request_type == FNET_TFTP_REQUEST_READ) && (tftp_if->packet_data.opcode == FNET_HTONS(FNET_TFTP_OPCODE_DATA)) )
  275. {
  276. if(tftp_if->server_port == 0)
  277. tftp_if->server_port = addr.sa_port; /* Save port of the first session only. */
  278. /* Is it our session. */
  279. if(tftp_if->server_port == addr.sa_port)
  280. {
  281. /* Send ACK */
  282. tftp_if->packet_ack.opcode = FNET_HTONS(FNET_TFTP_OPCODE_ACK);
  283. sendto(tftp_if->socket_client, (char*)&tftp_if->packet_ack, sizeof(struct fnet_tftp_packet_ack), 0,
  284. (struct sockaddr*)&addr, sizeof(addr) );
  285. /* Reset timeout. */
  286. tftp_if->last_time = fnet_timer_ticks();
  287. /* Message the application. */
  288. if((tftp_if->block_number_ack+1) == fnet_htons(tftp_if->packet_data.block_number))
  289. {
  290. tftp_if->block_number_ack ++;
  291. /* Call Rx handler. */
  292. if(tftp_if->handler(tftp_if->request_type, (unsigned char *)&tftp_if->packet_data.data[0], (unsigned short)(received - 4), FNET_OK, tftp_if->handler_param) == FNET_ERR)
  293. {
  294. tftp_if->state = FNET_TFTP_CLN_STATE_RELEASE;
  295. break;
  296. }
  297. /* Check return result.*/
  298. if(received < sizeof(struct fnet_tftp_packet_data)) /* EOF */
  299. {
  300. fnet_tftp_if.state = FNET_TFTP_CLN_STATE_RELEASE; /* => RELEASE */
  301. }
  302. }
  303. }
  304. }
  305. /* Received ACK. */
  306. else if ((tftp_if->request_type == FNET_TFTP_REQUEST_WRITE) && (tftp_if->packet_data.opcode == FNET_HTONS(FNET_TFTP_OPCODE_ACK)))
  307. {
  308. if(tftp_if->block_number_ack == 0)
  309. tftp_if->server_port = addr.sa_port; /* Save port number of the first ACK only. */
  310. /* Is it our session. */
  311. if(tftp_if->server_port == addr.sa_port)
  312. {
  313. if(tftp_if->block_number_ack == fnet_ntohs(tftp_if->packet_data.block_number)) /* Correct ACK. */
  314. {
  315. /* Last ACK. */
  316. if(tftp_if->block_number_ack && (tftp_if->tx_data_size < sizeof(tftp_if->packet_data.data)))
  317. {
  318. tftp_if->state = FNET_TFTP_CLN_STATE_RELEASE;
  319. break;
  320. }
  321. else /* More data to send. */
  322. {
  323. tftp_if->block_number_ack++;
  324. if((tftp_if->tx_data_size = tftp_if->handler(tftp_if->request_type, (unsigned char *)&tftp_if->packet_data.data[0],
  325. (unsigned short)(sizeof(tftp_if->packet_data.data)),
  326. FNET_OK, tftp_if->handler_param)) == FNET_ERR)
  327. {
  328. tftp_if->state = FNET_TFTP_CLN_STATE_RELEASE;
  329. break;
  330. }
  331. }
  332. }
  333. /* else: Resend last packet. */
  334. /* Send data. */
  335. tftp_if->packet_data.opcode = FNET_HTONS(FNET_TFTP_OPCODE_DATA);
  336. tftp_if->packet_data.block_number = fnet_htons(tftp_if->block_number_ack);
  337. sendto(tftp_if->socket_client, (char*)&tftp_if->packet_data, (4+tftp_if->tx_data_size), 0,
  338. &addr, sizeof(addr) );
  339. /* Reset timeout. */
  340. tftp_if->last_time = fnet_timer_ticks();
  341. }
  342. }
  343. /* Wrong opration. */
  344. else
  345. goto ERROR;
  346. }
  347. else
  348. {
  349. /* Check error. Check timeout */
  350. if((received == SOCKET_ERROR)||
  351. (fnet_timer_get_interval(tftp_if->last_time, fnet_timer_ticks()) > (fnet_tftp_if.timeout/FNET_TIMER_PERIOD_MS)))
  352. {
  353. goto ERROR;
  354. }
  355. }
  356. break;
  357. /*---- RELEASE -------------------------------------------------*/
  358. default:
  359. case FNET_TFTP_CLN_STATE_RELEASE:
  360. fnet_tftp_cln_release();
  361. break;
  362. }
  363. return;
  364. ERROR:
  365. tftp_if->state = FNET_TFTP_CLN_STATE_RELEASE; /* => RELEASE */
  366. tftp_if->handler(tftp_if->request_type, (unsigned char *)FNET_TFTP_DEFAULT_ERROR, 0, FNET_ERR, tftp_if->handler_param);
  367. }
  368. /************************************************************************
  369. * NAME: fnet_tftp_cln_release
  370. *
  371. * DESCRIPTION: TFTP-client release.
  372. ************************************************************************/
  373. void fnet_tftp_cln_release(void)
  374. {
  375. if(fnet_tftp_if.state != FNET_TFTP_CLN_STATE_DISABLED)
  376. {
  377. /* Close socket. */
  378. closesocket(fnet_tftp_if.socket_client);
  379. /* Unregister the tftp service. */
  380. fnet_poll_service_unregister( fnet_tftp_if.service_descriptor );
  381. fnet_tftp_if.state = FNET_TFTP_CLN_STATE_DISABLED;
  382. }
  383. }
  384. /************************************************************************
  385. * NAME: fnet_tftp_cln_state
  386. *
  387. * DESCRIPTION: This function returns a current state of the TFTP client.
  388. ************************************************************************/
  389. fnet_tftp_cln_state_t fnet_tftp_cln_state()
  390. {
  391. return fnet_tftp_if.state;
  392. }
  393. #endif