socket.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. // Copyright 2016 by BeeGee, see LICENSE.txt
  2. //
  3. // Adapted from: github.com/tuanpmt/esp_bridge, Created on: Mar 4, 2015, Author: Minh
  4. // Adapted from: rest.c, Author: Thorsten von Eicken
  5. #include "esp8266.h"
  6. #include "c_types.h"
  7. #include "ip_addr.h"
  8. #include "socket.h"
  9. #define SOCK_DBG
  10. #ifdef SOCK_DBG
  11. #define DBG_SOCK(format, ...) os_printf(format, ## __VA_ARGS__)
  12. #else
  13. #define DBG_SOCK(format, ...) do { } while(0)
  14. #endif
  15. typedef struct {
  16. char *host;
  17. uint32_t port;
  18. ip_addr_t ip;
  19. struct espconn *pCon;
  20. char *data;
  21. uint16_t data_len;
  22. uint16_t data_sent;
  23. uint32_t resp_cb;
  24. uint8_t conn_num;
  25. uint8_t sock_mode;
  26. } SocketClient;
  27. // Connection pool for TCP/UDP socket clients/servers. Attached MCU's just call SOCKET_setup and this allocates
  28. // a connection, They never call any 'free' and given that the attached MCU could restart at
  29. // any time, we cannot really rely on the attached MCU to call 'free' ever, so better do without.
  30. // Instead, we allocate a fixed pool of connections an round-robin. What this means is that the
  31. // attached MCU should really use at most as many SOCKET connections as there are slots in the pool.
  32. #define MAX_SOCKET 4
  33. #define MAX_RECEIVE_PACKET_LENGTH 100
  34. static SocketClient socketClient[MAX_SOCKET];
  35. static uint8_t socketNum = 0xff; // index into socketClient for next slot to allocate
  36. // Any incoming data?
  37. static void ICACHE_FLASH_ATTR
  38. socketclient_recv_cb(void *arg, char *pusrdata, unsigned short length) {
  39. struct espconn *pCon = (struct espconn *)arg;
  40. SocketClient* client = (SocketClient *)pCon->reverse;
  41. uint8_t clientNum = client->conn_num;
  42. uint8_t cb_type = USERCB_RECV;
  43. DBG_SOCK("SOCKET #%d: Received %d bytes: %s\n", client-socketClient, length, pusrdata);
  44. unsigned short position = 0;
  45. do
  46. {
  47. unsigned short msgLen = length - position;
  48. if( msgLen > MAX_RECEIVE_PACKET_LENGTH )
  49. msgLen = MAX_RECEIVE_PACKET_LENGTH;
  50. cmdResponseStart(CMD_RESP_CB, client->resp_cb, 4);
  51. cmdResponseBody(&cb_type, 1);
  52. cmdResponseBody(&clientNum, 1);
  53. cmdResponseBody(&msgLen, 2);
  54. cmdResponseBody(pusrdata + position, msgLen);
  55. cmdResponseEnd();
  56. position += msgLen;
  57. }while(position < length );
  58. if (client->sock_mode != SOCKET_TCP_SERVER) { // We don't wait for a response
  59. DBG_SOCK("SOCKET #%d: disconnect after receiving\n", client-socketClient);
  60. espconn_disconnect(client->pCon); // disconnect from the server
  61. }
  62. }
  63. // Data is sent
  64. static void ICACHE_FLASH_ATTR
  65. socketclient_sent_cb(void *arg) {
  66. struct espconn *pCon = (struct espconn *)arg;
  67. SocketClient* client = (SocketClient *)pCon->reverse;
  68. uint8_t clientNum = client->conn_num;
  69. uint8_t cb_type = USERCB_SENT;
  70. DBG_SOCK("SOCKET #%d: Sent\n", client-socketClient);
  71. sint16 sentDataLen = client->data_sent;
  72. if (client->data_sent != client->data_len)
  73. {
  74. // we only sent part of the buffer, send the rest
  75. uint16_t data_left = client->data_len - client->data_sent;
  76. if (data_left > 1400) // we have more than 1400 bytes left
  77. {
  78. data_left = 1400;
  79. espconn_sent(client->pCon, (uint8_t*)(client->data+client->data_sent), 1400 );
  80. }
  81. espconn_sent(client->pCon, (uint8_t*)(client->data+client->data_sent), data_left );
  82. client->data_sent += data_left;
  83. }
  84. else
  85. {
  86. // we're done sending, free the memory
  87. if (client->data) os_free(client->data);
  88. client->data = 0;
  89. if (client->sock_mode == SOCKET_TCP_CLIENT) { // We don't wait for a response
  90. DBG_SOCK("SOCKET #%d: disconnect after sending\n", clientNum);
  91. espconn_disconnect(client->pCon);
  92. }
  93. cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
  94. cmdResponseBody(&cb_type, 1);
  95. cmdResponseBody(&clientNum, 1);
  96. cmdResponseBody(&sentDataLen, 2);
  97. cmdResponseEnd();
  98. }
  99. }
  100. // Connection is disconnected
  101. static void ICACHE_FLASH_ATTR
  102. socketclient_discon_cb(void *arg) {
  103. struct espconn *pespconn = (struct espconn *)arg;
  104. SocketClient* client = (SocketClient *)pespconn->reverse;
  105. uint8_t clientNum = client->conn_num;
  106. uint8_t cb_type = USERCB_CONN;
  107. sint16 _status = CONNSTAT_DIS;
  108. DBG_SOCK("SOCKET #%d: Disconnect\n", clientNum);
  109. // free the data buffer, if we have one
  110. if (client->data) os_free(client->data);
  111. client->data = 0;
  112. cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
  113. cmdResponseBody(&cb_type, 1);
  114. cmdResponseBody(&clientNum, 1);
  115. cmdResponseBody(&_status, 2);
  116. cmdResponseEnd();
  117. }
  118. // Connection was reset
  119. static void ICACHE_FLASH_ATTR
  120. socketclient_recon_cb(void *arg, sint8 errType) {
  121. struct espconn *pCon = (struct espconn *)arg;
  122. SocketClient* client = (SocketClient *)pCon->reverse;
  123. uint8_t clientNum = client->conn_num;
  124. uint8_t cb_type = USERCB_RECO;
  125. sint16 _errType = errType;
  126. os_printf("SOCKET #%d: conn reset, err=%d\n", clientNum, _errType);
  127. cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
  128. cmdResponseBody(&cb_type, 1);
  129. cmdResponseBody(&clientNum, 1);
  130. cmdResponseBody(&_errType, 2);
  131. cmdResponseEnd();
  132. // free the data buffer, if we have one
  133. if (client->data) os_free(client->data);
  134. client->data = 0;
  135. }
  136. // Connection is done
  137. static void ICACHE_FLASH_ATTR
  138. socketclient_connect_cb(void *arg) {
  139. struct espconn *pCon = (struct espconn *)arg;
  140. SocketClient* client = (SocketClient *)pCon->reverse;
  141. uint8_t clientNum = client->conn_num;
  142. uint8_t cb_type = USERCB_CONN;
  143. sint16 _status = CONNSTAT_CON;
  144. DBG_SOCK("SOCKET #%d: connected socket mode = %d\n", clientNum, client->sock_mode);
  145. espconn_regist_disconcb(client->pCon, socketclient_discon_cb);
  146. espconn_regist_recvcb(client->pCon, socketclient_recv_cb);
  147. espconn_regist_sentcb(client->pCon, socketclient_sent_cb);
  148. DBG_SOCK("SOCKET #%d: sending %d\n", clientNum, client->data_sent);
  149. if (client->sock_mode != SOCKET_TCP_SERVER) { // Send data after established connection only in client mode
  150. client->data_sent = client->data_len <= 1400 ? client->data_len : 1400;
  151. DBG_SOCK("SOCKET #%d: sending %d\n", clientNum, client->data_sent);
  152. espconn_send(client->pCon, (uint8_t*)client->data, client->data_sent);
  153. }
  154. cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
  155. cmdResponseBody(&cb_type, 1);
  156. cmdResponseBody(&clientNum, 1);
  157. cmdResponseBody(&_status, 2);
  158. cmdResponseEnd();
  159. }
  160. static void ICACHE_FLASH_ATTR
  161. socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) {
  162. struct espconn *pConn = (struct espconn *)arg;
  163. SocketClient* client = (SocketClient *)pConn->reverse;
  164. uint8_t clientNum = client->conn_num;
  165. if(ipaddr == NULL) {
  166. sint16 _errType = ESPCONN_RTE; //-4;
  167. uint8_t cb_type = USERCB_RECO; // use Routing problem or define a new one
  168. os_printf("SOCKET #%d DNS: Got no ip, report error\n", clientNum);
  169. cmdResponseStart(CMD_RESP_CB, client->resp_cb, 3);
  170. cmdResponseBody(&cb_type, 2); // Same as connection reset?? or define a new one
  171. cmdResponseBody(&clientNum, 1);
  172. cmdResponseBody(&_errType, 2);
  173. cmdResponseEnd();
  174. return;
  175. }
  176. DBG_SOCK("SOCKET #%d DNS: found ip %d.%d.%d.%d\n",
  177. clientNum,
  178. *((uint8 *) &ipaddr->addr),
  179. *((uint8 *) &ipaddr->addr + 1),
  180. *((uint8 *) &ipaddr->addr + 2),
  181. *((uint8 *) &ipaddr->addr + 3));
  182. if(client->ip.addr == 0 && ipaddr->addr != 0) {
  183. os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);
  184. espconn_connect(client->pCon);
  185. DBG_SOCK("SOCKET #%d: connecting...\n", clientNum);
  186. }
  187. }
  188. void ICACHE_FLASH_ATTR
  189. SOCKET_Setup(CmdPacket *cmd) {
  190. CmdRequest req;
  191. uint16_t port;
  192. uint8_t sock_mode;
  193. int32_t err = -1; // error code in case of failure
  194. // start parsing the command
  195. cmdRequest(&req, cmd);
  196. if(cmdGetArgc(&req) != 3) {
  197. DBG_SOCK("SOCKET Setup parse command failure: (cmdGetArgc(&req) != 3)\n");
  198. goto fail;
  199. }
  200. err--;
  201. // get the hostname (IP address)
  202. uint16_t len = cmdArgLen(&req);
  203. if (len > 128) {
  204. DBG_SOCK("SOCKET Setup parse command failure: hostname longer than 128 characters\n");
  205. goto fail; // safety check
  206. }
  207. err--;
  208. uint8_t *socket_host = (uint8_t*)os_zalloc(len + 1);
  209. if (socket_host == NULL) {
  210. DBG_SOCK("SOCKET Setup failed to alloc memory for socket_host\n");
  211. goto fail;
  212. }
  213. if (cmdPopArg(&req, socket_host, len)) {
  214. DBG_SOCK("SOCKET Setup parse command failure: (cmdPopArg(&req, socket_host, len))\n");
  215. goto fail;
  216. }
  217. err--;
  218. socket_host[len] = 0;
  219. // get the port
  220. if (cmdPopArg(&req, (uint8_t*)&port, 2)) {
  221. DBG_SOCK("SOCKET Setup parse command failure: cannot get port\n");
  222. os_free(socket_host);
  223. goto fail;
  224. }
  225. err--;
  226. // get the socket mode
  227. if (cmdPopArg(&req, (uint8_t*)&sock_mode, 1)) {
  228. DBG_SOCK("SOCKET Setup parse command failure: cannot get mode\n");
  229. os_free(socket_host);
  230. goto fail;
  231. }
  232. err--;
  233. DBG_SOCK("SOCKET Setup listener flag\n");
  234. // clear connection structures the first time
  235. if (socketNum == 0xff) {
  236. os_memset(socketClient, 0, MAX_SOCKET * sizeof(SocketClient));
  237. socketNum = 0;
  238. }
  239. // allocate a connection structure
  240. SocketClient *client = socketClient + socketNum;
  241. uint8_t clientNum = socketNum;
  242. socketNum = (socketNum+1)%MAX_SOCKET;
  243. // free any data structure that may be left from a previous connection
  244. if (client->data) os_free(client->data);
  245. if (client->pCon) {
  246. if (sock_mode != SOCKET_UDP) {
  247. if (client->pCon->proto.tcp) os_free(client->pCon->proto.tcp);
  248. } else {
  249. if (client->pCon->proto.udp) os_free(client->pCon->proto.udp);
  250. }
  251. os_free(client->pCon);
  252. }
  253. os_memset(client, 0, sizeof(SocketClient));
  254. DBG_SOCK("SOCKET #%d: Setup host=%s port=%d \n", clientNum, socket_host, port);
  255. client->sock_mode = sock_mode;
  256. client->resp_cb = cmd->value;
  257. client->conn_num = clientNum;
  258. client->host = (char *)socket_host;
  259. client->port = port;
  260. if (sock_mode == SOCKET_UDP) {
  261. wifi_set_broadcast_if(STATIONAP_MODE);
  262. }
  263. client->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
  264. if (client->pCon == NULL) {
  265. DBG_SOCK("SOCKET #%d: Setup failed to alloc memory for client_pCon\n", clientNum);
  266. goto fail;
  267. }
  268. if (sock_mode != SOCKET_UDP) {
  269. client->pCon->type = ESPCONN_TCP;
  270. client->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
  271. if (client->pCon->proto.tcp == NULL) {
  272. DBG_SOCK("SOCKET #%d: Setup failed to alloc memory for client->pCon->proto.tcp\n", clientNum);
  273. goto fail;
  274. }
  275. } else {
  276. client->pCon->type = ESPCONN_UDP;
  277. client->pCon->proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp));
  278. if (client->pCon->proto.udp == NULL) {
  279. DBG_SOCK("SOCKET #%d: Setup failed to alloc memory for client->pCon->proto.udp\n", clientNum);
  280. goto fail;
  281. }
  282. }
  283. client->pCon->state = ESPCONN_NONE;
  284. os_memcpy(client->host, socket_host, 4);
  285. if (sock_mode != SOCKET_UDP) {
  286. client->pCon->proto.tcp->remote_port = client->port;
  287. client->pCon->proto.tcp->local_port = client->port; // espconn_port();
  288. } else {
  289. client->pCon->proto.udp->remote_port = client->port;
  290. client->pCon->proto.udp->local_port = client->port;
  291. }
  292. client->pCon->reverse = client;
  293. espconn_regist_sentcb(client->pCon, socketclient_sent_cb);
  294. espconn_regist_recvcb(client->pCon, socketclient_recv_cb);
  295. if (sock_mode == SOCKET_UDP) {
  296. DBG_SOCK("SOCKET #%d: Create connection to ip %s:%d\n", clientNum, client->host, client->port);
  297. if(UTILS_StrToIP((char *)client->host, &client->pCon->proto.udp->remote_ip)) {
  298. espconn_create(client->pCon);
  299. } else {
  300. DBG_SOCK("SOCKET #%d: failed to copy remote_ip to &client->pCon->proto.udp->remote_ip\n", clientNum);
  301. goto fail;
  302. }
  303. } else {
  304. espconn_regist_reconcb(client->pCon, socketclient_recon_cb);
  305. if (client->sock_mode == SOCKET_TCP_SERVER) { // Server mode?
  306. DBG_SOCK("SOCKET #%d: Enable server mode on port%d\n", clientNum, client->port);
  307. espconn_accept(client->pCon);
  308. espconn_regist_connectcb(client->pCon, socketclient_connect_cb);
  309. }
  310. }
  311. cmdResponseStart(CMD_RESP_V, clientNum, 0);
  312. cmdResponseEnd();
  313. DBG_SOCK("SOCKET #%d: setup finished\n", clientNum);
  314. return;
  315. fail:
  316. cmdResponseStart(CMD_RESP_V, err, 0);
  317. cmdResponseEnd();
  318. return;
  319. }
  320. void ICACHE_FLASH_ATTR
  321. SOCKET_Send(CmdPacket *cmd) {
  322. CmdRequest req;
  323. cmdRequest(&req, cmd);
  324. // Get client
  325. uint32_t clientNum = cmd->value;
  326. SocketClient *client = socketClient + (clientNum % MAX_SOCKET);
  327. DBG_SOCK("SOCKET #%d: send", clientNum);
  328. if (cmd->argc != 1 && cmd->argc != 2) {
  329. DBG_SOCK("\nSOCKET #%d: send - wrong number of arguments\n", clientNum);
  330. return;
  331. }
  332. // Get data to sent
  333. client->data_len = cmdArgLen(&req);
  334. DBG_SOCK(" dataLen=%d", client->data_len);
  335. if (client->data) os_free(client->data);
  336. client->data = (char*)os_zalloc(client->data_len);
  337. if (client->data == NULL) {
  338. DBG_SOCK("\nSOCKET #%d failed to alloc memory for client->data\n", clientNum);
  339. goto fail;
  340. }
  341. cmdPopArg(&req, client->data, client->data_len);
  342. DBG_SOCK(" socketData=%s", client->data);
  343. // client->data_len = os_sprintf((char*)client->data, socketDataSet, socketData);
  344. DBG_SOCK("\n");
  345. DBG_SOCK("SOCKET #%d: Create connection to ip %s:%d\n", clientNum, client->host, client->port);
  346. if (client->sock_mode == SOCKET_TCP_SERVER) { // In TCP server mode we should be connected already and send the data immediately
  347. remot_info *premot = NULL;
  348. if (espconn_get_connection_info(client->pCon,&premot,0) == ESPCONN_OK){
  349. for (uint8 count = 0; count < client->pCon->link_cnt; count ++){
  350. client->pCon->proto.tcp->remote_port = premot[count].remote_port;
  351. client->pCon->proto.tcp->remote_ip[0] = premot[count].remote_ip[0];
  352. client->pCon->proto.tcp->remote_ip[1] = premot[count].remote_ip[1];
  353. client->pCon->proto.tcp->remote_ip[2] = premot[count].remote_ip[2];
  354. client->pCon->proto.tcp->remote_ip[3] = premot[count].remote_ip[3];
  355. DBG_SOCK("SOCKET #%d: connected to %d.%d.%d.%d:%d\n",
  356. clientNum,
  357. client->pCon->proto.tcp->remote_ip[0],
  358. client->pCon->proto.tcp->remote_ip[1],
  359. client->pCon->proto.tcp->remote_ip[2],
  360. client->pCon->proto.tcp->remote_ip[3],
  361. client->pCon->proto.tcp->remote_port
  362. );
  363. }
  364. client->data_sent = client->data_len <= 1400 ? client->data_len : 1400;
  365. DBG_SOCK("SOCKET #%d: Server sending %d\n", clientNum, client->data_sent);
  366. espconn_send(client->pCon, (uint8_t*)client->data, client->data_sent);
  367. }
  368. } else if (client->sock_mode != SOCKET_UDP) { // In TCP client mode we connect and send the data from the connected callback
  369. espconn_regist_connectcb(client->pCon, socketclient_connect_cb);
  370. if(UTILS_StrToIP((char *)client->host, &client->pCon->proto.tcp->remote_ip)) {
  371. DBG_SOCK("SOCKET #%d: Connect to ip %s:%d\n", clientNum, client->host, client->port);
  372. espconn_connect(client->pCon);
  373. } else {
  374. DBG_SOCK("SOCKET #%d: Connect to host %s:%d\n", clientNum, client->host, client->port);
  375. espconn_gethostbyname(client->pCon, (char *)client->host, &client->ip, socket_dns_found);
  376. }
  377. } else { // in UDP socket mode we send the data immediately
  378. client->data_sent = client->data_len <= 1400 ? client->data_len : 1400;
  379. DBG_SOCK("SOCKET #%d: sending %d bytes: %s\n", clientNum, client->data_sent, client->data);
  380. espconn_sent(client->pCon, (uint8_t*)client->data, client->data_sent);
  381. }
  382. return;
  383. fail:
  384. DBG_SOCK("\n");
  385. }