PageRenderTime 27ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/erlang_interface.c

http://github.com/luisbebop/erlang_interface
C | 573 lines | 399 code | 92 blank | 82 comment | 79 complexity | 3620a9adc3dd1c831beb151028c4039a MD5 | raw file
  1. #include "erlang_interface.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <netdb.h>
  10. // socket handle
  11. int socket_handle;
  12. int ei_encode_list_header(char *buf, int *index, int arity)
  13. {
  14. char *s = buf + *index;
  15. char *s0 = s;
  16. if (arity < 0) return -1;
  17. else if (arity > 0) {
  18. if (!buf) s += 5;
  19. else {
  20. put8(s,ERL_LIST_EXT);
  21. put32be(s,arity);
  22. }
  23. }
  24. else {
  25. /* empty list */
  26. if (!buf) s++;
  27. else put8(s,ERL_NIL_EXT);
  28. }
  29. *index += s-s0;
  30. return 0;
  31. }
  32. int ei_encode_tuple_header(char *buf, int *index, int arity)
  33. {
  34. char *s = buf + *index;
  35. char *s0 = s;
  36. if (arity < 0) return -1;
  37. if (arity <= 0xff) {
  38. if (!buf) s += 2;
  39. else {
  40. put8(s,ERL_SMALL_TUPLE_EXT);
  41. put8(s,arity);
  42. }
  43. }
  44. else {
  45. if (!buf) s += 5;
  46. else {
  47. put8(s,ERL_LARGE_TUPLE_EXT);
  48. put32be(s,arity);
  49. }
  50. }
  51. *index += s-s0;
  52. return 0;
  53. }
  54. int ei_encode_binary(char *buf, int *index, const void *p, long len)
  55. {
  56. char *s = buf + *index;
  57. char *s0 = s;
  58. if (!buf) s += 5;
  59. else {
  60. put8(s,ERL_BINARY_EXT);
  61. put32be(s,len);
  62. memmove(s,p,len);
  63. }
  64. s += len;
  65. *index += s-s0;
  66. return 0;
  67. }
  68. int ei_encode_atom_len(char *buf, int *index, const char *p, int len)
  69. {
  70. char *s = buf + *index;
  71. char *s0 = s;
  72. /* This function is documented to truncate at MAXATOMLEN (256) */
  73. if (len > MAXATOMLEN)
  74. len = MAXATOMLEN;
  75. if (!buf) s += 3;
  76. else {
  77. put8(s,ERL_ATOM_EXT);
  78. put16be(s,len);
  79. memmove(s,p,len); /* unterminated string */
  80. }
  81. s += len;
  82. *index += s-s0;
  83. return 0;
  84. }
  85. int ei_encode_atom(char *buf, int *index, const char *p)
  86. {
  87. return ei_encode_atom_len(buf, index, p, strlen(p));
  88. }
  89. int ei_encode_long(char *buf, int *index, long p)
  90. {
  91. char *s = buf + *index;
  92. char *s0 = s;
  93. if ((p < 256) && (p >= 0)) {
  94. if (!buf) s += 2;
  95. else {
  96. put8(s,ERL_SMALL_INTEGER_EXT);
  97. put8(s,(p & 0xff));
  98. }
  99. }
  100. else if ((p <= ERL_MAX) && (p >= ERL_MIN)) {
  101. /* FIXME: Non optimal, could use (p <= LONG_MAX) && (p >= LONG_MIN)
  102. and skip next case */
  103. if (!buf) s += 5;
  104. else {
  105. put8(s,ERL_INTEGER_EXT);
  106. put32be(s,p);
  107. }
  108. }
  109. else {
  110. if (!buf) s += 7;
  111. else {
  112. put8(s,ERL_SMALL_BIG_EXT);
  113. put8(s,4); /* len = four bytes */
  114. put8(s, p < 0); /* save sign separately */
  115. // problem here. Some plataforms don't have abs ... :(
  116. //put32le(s, abs(p)); /* OBS: Little Endian, and p now positive */
  117. put32le(s,p);
  118. }
  119. }
  120. *index += s-s0;
  121. return 0;
  122. }
  123. /* add the version identifier to the start of the buffer */
  124. int ei_encode_version(char *buf, int *index)
  125. {
  126. char *s = buf + *index;
  127. char *s0 = s;
  128. if (!buf) s ++;
  129. else put8(s,(unsigned char)ERL_VERSION_MAGIC);
  130. *index += s-s0;
  131. return 0;
  132. }
  133. // util functions
  134. char *upb_put_v_uint64_t(char *buf, unsigned long val)
  135. {
  136. do {
  137. unsigned char byte = val & 0x7f;
  138. val >>= 7;
  139. if(val) byte |= 0x80;
  140. *buf++ = byte;
  141. } while(val);
  142. return buf;
  143. }
  144. char *upb_put_v_uint32_t(char *buf, unsigned int val)
  145. {
  146. return upb_put_v_uint64_t(buf, val);
  147. }
  148. int pb_add_request(char *buf, int *index, const void *p, long len)
  149. {
  150. char *s = buf + *index;
  151. char *s0 = s;
  152. if (!buf) s ++;
  153. else {
  154. put8(s,(unsigned char)0x17);
  155. put8(s,(unsigned char)0x0A);
  156. s = upb_put_v_uint32_t(s, len);
  157. memmove(s,p,len);
  158. }
  159. s += len;
  160. *index += s-s0;
  161. return 0;
  162. }
  163. int pb_add_content_type(char * buf, int *index)
  164. {
  165. char *s = buf + *index;
  166. char *s0 = s;
  167. char p[28];
  168. int len;
  169. memset(p,0,sizeof(p));
  170. strcpy(p,"application/x-erlang-binary");
  171. len = strlen(p);
  172. if (!buf) s ++;
  173. else {
  174. put8(s,0x12);
  175. put8(s,0x1B);
  176. memmove(s,p,len);
  177. }
  178. s += len;
  179. *index += s-s0;
  180. return 0;
  181. }
  182. void hex_dump(unsigned char *data, int size, char *caption)
  183. {
  184. int i; // index in data...
  185. int j; // index in line...
  186. char temp[8];
  187. char buffer[128];
  188. char *ascii;
  189. memset(buffer, 0, 128);
  190. printf("---------> %s <--------- (%d bytes from %p)\n", caption, size, data);
  191. // Printing the ruler...
  192. printf(" +0 +4 +8 +c 0 4 8 c \n");
  193. // Hex portion of the line is 8 (the padding) + 3 * 16 = 52 chars long
  194. // We add another four bytes padding and place the ASCII version...
  195. ascii = buffer + 58;
  196. memset(buffer, ' ', 58 + 16);
  197. buffer[58 + 16] = '\n';
  198. buffer[58 + 17] = '\0';
  199. buffer[0] = '+';
  200. buffer[1] = '0';
  201. buffer[2] = '0';
  202. buffer[3] = '0';
  203. buffer[4] = '0';
  204. for (i = 0, j = 0; i < size; i++, j++)
  205. {
  206. if (j == 16)
  207. {
  208. printf("%s", buffer);
  209. memset(buffer, ' ', 58 + 16);
  210. sprintf(temp, "+%04x", i);
  211. memcpy(buffer, temp, 5);
  212. j = 0;
  213. }
  214. sprintf(temp, "%02x", 0xff & data[i]);
  215. memcpy(buffer + 8 + (j * 3), temp, 2);
  216. if ((data[i] > 31) && (data[i] < 127))
  217. ascii[j] = data[i];
  218. else
  219. ascii[j] = '.';
  220. }
  221. if (j != 0)
  222. printf("%s", buffer);
  223. }
  224. #define LOWORD(l) ((unsigned short)((l) & 0xffff))
  225. #define HIWORD(l) ((unsigned short)((l) >> 16))
  226. #define LOBYTE(w) ((unsigned char)((w) & 0xff))
  227. #define HIBYTE(w) ((unsigned char)((w) >> 8))
  228. #define HH(x) HIBYTE(HIWORD( x ))
  229. #define HL(x) LOBYTE(HIWORD( x ))
  230. #define LH(x) HIBYTE(LOWORD( x ))
  231. #define LL(x) LOBYTE(LOWORD( x ))
  232. #define MAKEWORD(a, b) ((unsigned short)(((unsigned char)((a) & 0xff)) | ((unsigned short)((unsigned char)((b) & 0xff))) << 8))
  233. #define MAKELONG(low,high) ((int)(((unsigned short)(low)) | (((unsigned int)((unsigned short)(high))) << 16)))
  234. void error(const char *msg)
  235. {
  236. perror(msg);
  237. exit(0);
  238. }
  239. int connect_(int argc, char *argv[])
  240. {
  241. int sockfd, portno, n;
  242. struct sockaddr_in serv_addr;
  243. struct hostent *server;
  244. if (argc < 3) {
  245. fprintf(stderr,"usage %s hostname port\n", argv[0]);
  246. exit(0);
  247. }
  248. portno = atoi(argv[2]);
  249. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  250. if (sockfd < 0) error("ERROR opening socket");
  251. server = gethostbyname(argv[1]);
  252. if (server == NULL) {
  253. fprintf(stderr,"ERROR, no such host\n");
  254. exit(0);
  255. }
  256. bzero((char *) &serv_addr, sizeof(serv_addr));
  257. serv_addr.sin_family = AF_INET;
  258. bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
  259. serv_addr.sin_port = htons(portno);
  260. if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
  261. error("ERROR connecting");
  262. //close(sockfd);
  263. return sockfd;
  264. }
  265. int UCLSend(unsigned char * buf, int len)
  266. {
  267. int n;
  268. n = write(socket_handle,buf,len);
  269. if (n < 0)
  270. error("ERROR writing to socket");
  271. return n;
  272. }
  273. int UCLReceive(unsigned char * buf, int maxlen)
  274. {
  275. int n;
  276. n = read(socket_handle,buf,maxlen);
  277. if (n < 0)
  278. error("ERROR reading from socket");
  279. return n;
  280. }
  281. // -1: erro de comunicação
  282. // -2: erro na resposta do mapreduce
  283. // -3: erro ao abrir arquivo para escrita
  284. int riak_mapreduce_request( char * bucket_name, char * key, char * erlang_module, char * map_function,
  285. char * serial_terminal, char * versao_walk, char * filename, char * crc_file, char * posxml_buffer,
  286. char * response, char * save_to_file, int * ret_code)
  287. {
  288. char buf[2048];
  289. unsigned char packet_send[2048];
  290. unsigned char packet_recv[1024];
  291. int index = 0, index_packet = 0, recvd = 0, size_to_receive = 0, total_size = 0, i = 0, size_block = 0, len_recv = 0, ret_size = 0;
  292. FILE *fp = NULL;
  293. memset(buf,0,sizeof(buf));
  294. memset(packet_send,0,sizeof(packet_send));
  295. memset(packet_recv,0,sizeof(packet_recv));
  296. // version
  297. ei_encode_version(buf,&index);
  298. // list do mapreduce contendo 3 tuples
  299. ei_encode_list_header(buf, &index, 3);
  300. // tuple 1: inputs
  301. ei_encode_tuple_header(buf,&index, 2);
  302. // atom inputs
  303. ei_encode_atom(buf,&index,"inputs");
  304. // list do inputs
  305. ei_encode_list_header(buf, &index, 1);
  306. // tuple contendo 2 elementos binários, bucket and key
  307. ei_encode_tuple_header(buf,&index, 2);
  308. // elemento binário bucket
  309. ei_encode_binary(buf, &index, bucket_name, strlen(bucket_name));
  310. // elemento binário key
  311. ei_encode_binary(buf, &index, key, strlen(key));
  312. // fim da list do inputs
  313. ei_encode_list_header(buf, &index, 0);
  314. // tuple 2: query
  315. ei_encode_tuple_header(buf,&index, 2);
  316. // atom query
  317. ei_encode_atom(buf,&index,"query");
  318. // list da query
  319. ei_encode_list_header(buf, &index, 1);
  320. // tuple contendo 4 elementos, { map, {modfun,Module,Function}, args, true }
  321. ei_encode_tuple_header(buf,&index, 4);
  322. // primeiro elemento, atom type
  323. ei_encode_atom(buf,&index,"map");
  324. // segundo elemento, nova tuple contendo 3 atoms
  325. ei_encode_tuple_header(buf,&index, 3);
  326. // primeiro atom do segundo elemento, modfun
  327. ei_encode_atom(buf,&index,"modfun");
  328. // segundo atom do segundo elemento, Module
  329. ei_encode_atom(buf,&index,erlang_module);
  330. // terceiro atom do segundo elemento, Function
  331. ei_encode_atom(buf,&index,map_function);
  332. // terceiro elemento, uma list com parâmetros do walk
  333. ei_encode_list_header(buf, &index, 5);
  334. // elemento binário serialterminal
  335. ei_encode_binary(buf, &index, serial_terminal, strlen(serial_terminal));
  336. // elemento binário versão walk
  337. ei_encode_binary(buf, &index, versao_walk, strlen(versao_walk));
  338. // elemento binário nomeaplicativo
  339. ei_encode_binary(buf, &index, filename, strlen(filename));
  340. // elemento binário crc aplicativo
  341. ei_encode_binary(buf, &index, crc_file, strlen(crc_file));
  342. // elemento binário buffer do posxml
  343. ei_encode_binary(buf, &index, posxml_buffer, strlen(posxml_buffer));
  344. // fim da list com parâmetros do walk
  345. ei_encode_list_header(buf, &index, 0);
  346. // quarto elemento, atom true
  347. ei_encode_atom(buf,&index,"true");
  348. // fim da list da query
  349. ei_encode_list_header(buf, &index, 0);
  350. // tuple 3: timeout
  351. ei_encode_tuple_header(buf,&index, 2);
  352. // atom timeout
  353. ei_encode_atom(buf,&index,"timeout");
  354. // integer timeout
  355. ei_encode_long(buf, &index, 5000);
  356. // fim da list do mapreduce contendo 3 tuples
  357. ei_encode_list_header(buf, &index, 0);
  358. // add request to protocol buffers message
  359. pb_add_request(&packet_send[4], &index_packet, buf, index);
  360. // add content_type to protocol buffers message
  361. pb_add_content_type(&packet_send[4], &index_packet);
  362. // add size to packet_send
  363. packet_send[0] = HH(index_packet);
  364. packet_send[1] = HL(index_packet);
  365. packet_send[2] = LH(index_packet);
  366. packet_send[3] = LL(index_packet);
  367. // sending buffer ...
  368. hex_dump(packet_send,index_packet+4,"sending");
  369. if (UCLSend(packet_send, index_packet+4) <= 0)
  370. {
  371. return -1;
  372. }
  373. // receiving buffer ...
  374. recvd = UCLReceive(packet_recv, sizeof(packet_recv));
  375. hex_dump(packet_recv, recvd, "received");
  376. if (recvd <= 0)
  377. {
  378. return -1;
  379. }
  380. // procura pelo inicio do binary term do erlang
  381. for(i = 0; i < recvd; i++)
  382. {
  383. if (packet_recv[i] == 0x83) break;
  384. }
  385. // não encontrou o inicio do binary term do erlang
  386. if (i >= recvd) {
  387. return -2;
  388. }
  389. // verifica o buffer recebido pelo pos enviado pelo Riak
  390. if (packet_recv[i] != 0x83 || packet_recv[i+1] != 0x6C || packet_recv[i+5] != 0x02 )
  391. {
  392. return -2;
  393. }
  394. // coloca o código de retorno da mensagem de mapreduce na variavel retcode
  395. *ret_code = packet_recv[i+7];
  396. // calcula o tamanho do buffer a ser recebido
  397. size_to_receive = MAKELONG(MAKEWORD(packet_recv[i+12],packet_recv[i+11]),MAKEWORD(packet_recv[i+10],packet_recv[i+9]));
  398. ret_size = size_to_receive;
  399. // subtrai o tamanho do header antes de chegar no elemento da list q contém o arquivo binário
  400. recvd -= (i+13); /* header size */
  401. // subtrai do tamanho de bytes a receber, com o tamanho do header e ultimo byte recebido
  402. size_to_receive -= recvd;
  403. // download de arquivo ou copia para buffer de memoria
  404. if (save_to_file)
  405. {
  406. // arquivo tem tamanho maior q 0
  407. if (ret_size > 0)
  408. {
  409. fp = fopen(save_to_file, "w");
  410. if (fp == NULL) return -3;
  411. if (size_to_receive <= 0) fwrite(&packet_recv[i+13],1,recvd - 1,fp);
  412. else fwrite(&packet_recv[i+13],1,recvd,fp);
  413. }
  414. }
  415. else
  416. {
  417. memcpy(response,&packet_recv[i+13], recvd);
  418. }
  419. // loop se necessario para baixar o restante do arquivo ou buffer
  420. i = 0;
  421. while(size_to_receive > 0)
  422. {
  423. if(size_to_receive > 1024) size_block = 1024;
  424. else size_block = size_to_receive;
  425. memset(packet_recv,0,sizeof(packet_recv));
  426. len_recv = UCLReceive(&packet_recv[0],size_block);
  427. printf("receiving = %d\n", len_recv);
  428. if(len_recv <= 0)
  429. {
  430. if (save_to_file && fp) fclose(fp);
  431. return -1;
  432. }
  433. if (save_to_file && fp)
  434. {
  435. // if ((size_to_receive - len_recv) <= 0) fwrite(packet_recv,1,len_recv - 1,fp);
  436. // else fwrite(packet_recv,1,len_recv,fp);
  437. fwrite(packet_recv,1,len_recv,fp);
  438. }
  439. else
  440. {
  441. memcpy(&response[total_size],packet_recv,len_recv);
  442. }
  443. size_to_receive -= len_recv;
  444. total_size += len_recv;
  445. i++;
  446. }
  447. if (save_to_file && fp) fclose(fp);
  448. return ret_size;
  449. }
  450. int main(int argc, char *argv[])
  451. {
  452. char buf[1024 * 32];
  453. int ret;
  454. int ret_code = 0;
  455. memset(buf,0,sizeof(buf));
  456. // connecting to host ... setting global handler
  457. socket_handle = connect_(argc,argv);
  458. // calling mapreduce_request to get a file, posxml: baixaarquivo
  459. // 0: enviando arquivo para o pos
  460. // 1: o arquivo do pos é igual ao arquivo do banco de dados
  461. // 2: o arquivo não foi encontrado
  462. // 3: serial number não autorizado
  463. // ret = riak_mapreduce_request( "assets", "tbk_teste2.posxml", "walk", "get_asset", // bucket, key, module, function
  464. // "521-661-006", "3.01", "tbk_inicio.posxml", "FFFF", "0,AAAAA,err,sn", // serial, version, app, crc, buffer
  465. // buf, "NULL7.dat", &ret_code);
  466. // calling mapreduce_request to get an app, posxml:
  467. // 0: enviando novo aplicativo
  468. // 1: enviando nova mensagem para mostrar no pos
  469. ret = riak_mapreduce_request("terminals", "tbk_123456", "walk", "request", // bucket, key, module, function
  470. "521-661-006", "3.01", "tbk_teste3.posxml", "FFFF", "0,AAAAA,err,sn", // serial, version, app, crc, buffer
  471. buf, "NULL10.dat", &ret_code);
  472. // calling mapreduce_request to get the company name:
  473. // 0: enviando company name
  474. // 1: erro na busca do serial
  475. // ret = riak_mapreduce_request( "serials", "123-321-123", "walk", "company", // bucket, key, module, function
  476. // "123-321-123", "3.01", "inicio.posxml", "FFFF", "0,AAAAA,err,sn", // serial, version, app, crc, buffer
  477. // buf, NULL, &ret_code);
  478. printf("ret = %d ret_code = %d\n", ret, ret_code);
  479. hex_dump(buf, ret, "response");
  480. return 0;
  481. }