/ClassMaster2014/barahon/Transcend_0.3_UnixSource/minorGems/network/linux/gnut_net.c

https://gitlab.com/garheade/linux_camp · C · 562 lines · 386 code · 118 blank · 58 comment · 75 complexity · 3da8ae12112cc5daf97b5a765a94cff1 MD5 · raw file

  1. /* Josh Pieper, (c) 2000 */
  2. /* This file is distributed under the GPL, see file COPYING for details */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sys/types.h>
  6. #ifndef WIN32
  7. #include <sys/time.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h>
  10. #include <net/if.h>
  11. #include <arpa/inet.h>
  12. #include <sys/ioctl.h>
  13. #include <unistd.h>
  14. #include <net/if.h>
  15. #include <netdb.h>
  16. #endif
  17. #include <errno.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <fcntl.h>
  21. #include <time.h>
  22. #include <pthread.h>
  23. #include <assert.h>
  24. #include "gnut_lib.h"
  25. #include "gnut_threads.h"
  26. #include "gnut_if.h"
  27. #include "protocol.h"
  28. uchar local_ip[4];
  29. // uint32 net_local_ip()
  30. //
  31. // returns the local ip address
  32. //
  33. uchar *net_local_ip()
  34. {
  35. return local_ip;
  36. }
  37. int gnut_net_host()
  38. {
  39. char host[256];
  40. struct hostent *he;
  41. int ret;
  42. g_debug(2,"entering\n");
  43. ret=gethostname(host,sizeof(host));
  44. if (ret<0) {
  45. perror("gnut_net_host, gethostname");
  46. return ret;
  47. }
  48. he=gethostbyname(host);
  49. if (he==NULL) {
  50. perror("gnut_net_host, gethostbyname");
  51. return ret;
  52. }
  53. memcpy(local_ip,he->h_addr_list[0],4);
  54. return 0;
  55. }
  56. // int net_init(char *iface)
  57. //
  58. // Does misc. net init stuff. Mostly just finds our local IP address
  59. //
  60. int net_init(char *iface)
  61. {
  62. struct sockaddr_in *sinptr=NULL;
  63. g_debug(2,"entering\n");
  64. if (iface!=NULL) {
  65. if (inet_aton(iface,(struct in_addr *) local_ip)) {
  66. g_debug(1,"local was set by command to: %i.%i.%i.%i\n",local_ip[0],local_ip[1],
  67. local_ip[2],local_ip[3]);
  68. return 0;
  69. }
  70. }
  71. if ((sinptr = get_if_addr(iface))==NULL) {
  72. g_debug(1,"Can't get local IP address through interface, trying host name...\n");
  73. gnut_net_host();
  74. } else {
  75. memcpy(local_ip,&(sinptr->sin_addr),sizeof(local_ip));
  76. }
  77. g_debug(1,"local ip is: %i.%i.%i.%i\n",local_ip[0],local_ip[1],
  78. local_ip[2],local_ip[3]);
  79. return 0;
  80. }
  81. // exactly like the real read, except that it returns -2
  82. // if no data was read before the timeout occurred...
  83. int timed_read(int sock, char *buf, int len, int secs)
  84. {
  85. fd_set fsr;
  86. struct timeval tv;
  87. int ret;
  88. ret=fcntl(sock,F_SETFL,O_NONBLOCK);
  89. FD_ZERO(&fsr);
  90. FD_SET(sock,&fsr);
  91. tv.tv_sec=secs;
  92. tv.tv_usec=0;
  93. ret=select(sock+1,&fsr,NULL,NULL,&tv);
  94. if (ret==0) {
  95. return -2;
  96. }
  97. if (ret<0) return ret;
  98. ret=read(sock,buf,len);
  99. fcntl(sock,F_SETFL,0);
  100. return ret;
  101. }
  102. // int timed_connect(int sock, struct sockaddr *sa,int addrlen,int secs)
  103. //
  104. // just like connect except that it times out after time secs
  105. // returns -2 on timeout, otherwise same as connect
  106. //
  107. int timed_connect(int sockfd, struct sockaddr *sa, int addrlen,int secs)
  108. {
  109. int ret;
  110. fd_set fsr;
  111. struct timeval tv;
  112. int val,len;
  113. g_debug(1,"entering sock=%i secs=%i\n",sockfd,secs);
  114. ret=fcntl(sockfd,F_SETFL,O_NONBLOCK);
  115. g_debug(5,"fcntl returned %i\n",ret);
  116. if (ret<0) return ret;
  117. ret=connect(sockfd,sa,addrlen);
  118. g_debug(5,"connect returned %i\n",ret);
  119. if (ret==0) {
  120. g_debug(0,"immediate connection!\n");
  121. // wooah! immediate connection
  122. return -2;
  123. }
  124. // if (errno != EINPROGRESS) {
  125. // perror("timed_connect, connect");
  126. // return ret;
  127. // }
  128. FD_ZERO(&fsr);
  129. FD_SET(sockfd,&fsr);
  130. tv.tv_sec=secs;
  131. tv.tv_usec=0;
  132. ret=select(sockfd+1,NULL,&fsr,NULL,&tv);
  133. g_debug(5,"select returned %i\n",ret);
  134. if (ret==0) {
  135. // timeout
  136. g_debug(1,"timeout\n");
  137. fcntl(sockfd,F_SETFL,0);
  138. return -2;
  139. }
  140. len=4;
  141. ret=getsockopt(sockfd,SOL_SOCKET,SO_ERROR,&val,&len);
  142. g_debug(5,"getsockopt returned %i val=%i\n",ret,val);
  143. if (ret<0) {
  144. g_debug(1,"getsockopt returned: %i\n",ret);
  145. return ret;
  146. }
  147. if (val!=0) {
  148. g_debug(3,"returning failure!\n");
  149. return -1;
  150. }
  151. ret=fcntl(sockfd,F_SETFL,0);
  152. g_debug(1,"fcntl: %i\n",ret);
  153. g_debug(3,"returning success val=%i\n",val);
  154. return 0;
  155. }
  156. // int create_listen_socket(int * port)
  157. //
  158. // attempts to create a socket to listen on port
  159. // returns the actual port bound to in port or <0 if not
  160. // successfull
  161. //
  162. int create_listen_socket(int *port)
  163. {
  164. struct sockaddr_in sin;
  165. int sock;
  166. int ret,i;
  167. int val;
  168. g_debug(3,"entering\n");
  169. sock=socket(AF_INET,SOCK_STREAM,6);
  170. if (sock<0) {
  171. perror("create_listen_socket, socket");
  172. return sock;
  173. }
  174. val=1;
  175. ret=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val));
  176. i=0;
  177. ret=-1;
  178. while (ret<0) {
  179. sin.sin_addr.s_addr=INADDR_ANY;
  180. sin.sin_port=htons(*port);
  181. sin.sin_family=AF_INET;
  182. ret=bind(sock,(struct sockaddr *) &sin,sizeof(struct sockaddr_in));
  183. if (++i>50) {
  184. (*port)++;
  185. i=0;
  186. }
  187. }
  188. if (ret<0) {
  189. perror("create_listen_socket, bind");
  190. return ret;
  191. }
  192. ret=listen(sock,5);
  193. if (ret<0) {
  194. perror("create_listen_socket, listen");
  195. return ret;
  196. }
  197. g_debug(1,"bound to port %i\n",*port);
  198. printf("Bound to port: %i\n",*port);
  199. ret=fcntl(sock,F_SETFL,O_NONBLOCK);
  200. if (ret<0) {
  201. perror("create_listen_socket, fcntl");
  202. return ret;
  203. }
  204. return sock;
  205. }
  206. // int read_line(int sock, char *buf, int len)
  207. //
  208. // reads a line from sock into buf, not exceeding len chars
  209. // returns 0 on EOF, -1 on error, or num of characters read
  210. // and -2 if buffer length exceeded
  211. //
  212. int read_line(int sock, char *buf, int len)
  213. {
  214. int i,ret;
  215. char c;
  216. char *ptr;
  217. ptr=buf;
  218. g_debug(3,"entering\n");
  219. fcntl(sock,F_SETFL,0);
  220. buf[0]=0;
  221. for (i=1;i<len;i++) {
  222. try_again:
  223. ret=timed_read(sock,&c,1,30);
  224. if (ret==1) {
  225. *ptr++=c;
  226. if (c=='\n') break;
  227. } else if (ret==0) {
  228. if (i==1) {
  229. return 0;
  230. } else break;
  231. } else {
  232. if (errno==EAGAIN)
  233. goto try_again;
  234. if (errno==EINTR)
  235. goto try_again;
  236. if (gnut_lib_debug>=1) perror("read_line, read");
  237. return -1;
  238. }
  239. }
  240. buf[i]=0;
  241. g_debug(3,"returning success\n");
  242. return i;
  243. }
  244. #ifndef PTHREADS_DRAFT4
  245. pthread_mutex_t make_connection_mutex=PTHREAD_MUTEX_INITIALIZER;
  246. #else
  247. pthread_mutex_t make_connection_mutex;
  248. #endif
  249. struct hostent *gnut_hostent_copy(struct hostent *he)
  250. {
  251. struct hostent *n;
  252. int i,len;
  253. if (!he) return NULL;
  254. n=(struct hostent *) calloc(sizeof(struct hostent),1);
  255. memcpy(n,he,sizeof(struct hostent));
  256. if (he->h_name) n->h_name=strdup(he->h_name);
  257. for (len=0;he->h_addr_list[len];len++);
  258. n->h_addr_list=(char **) calloc(sizeof(char *) * (len+1),1);
  259. for (i=0;i<len;i++) {
  260. n->h_addr_list[i]=xmalloc(4);
  261. memcpy(n->h_addr_list[i],he->h_addr_list[i],4);
  262. }
  263. return n;
  264. }
  265. void gnut_hostent_delete(struct hostent *he)
  266. {
  267. int i,len;
  268. g_debug(1,"entering\n");
  269. for (len=0;he->h_addr_list[len];len++);
  270. g_debug(1,"len=%i\n",len);
  271. for (i=0;i<len;i++) {
  272. g_debug(1,"deleting i=%i\n",i);
  273. if (he->h_addr_list[i]) free(he->h_addr_list[i]);
  274. }
  275. g_debug(1,"freeing h_name\n");
  276. if (he->h_name) free(he->h_name);
  277. g_debug(1,"freeing h_addr_list\n");
  278. free(he->h_addr_list);
  279. g_debug(1,"freeing he\n");
  280. free(he);
  281. g_debug(1,"returning\n");
  282. }
  283. // int make_connection(char *host, uint port, uchar ip[4])
  284. //
  285. // creates a socket, and attempts to make a connection to the host
  286. // named. it tries multiple resolved ip addresses if necessary,
  287. // returning the socket on success and storing the good ip number in ip
  288. // otherwise it returns <0
  289. //
  290. // Notes: due to the fact that gethostbyname is not thread safe
  291. // we need to protect this function with a mutex
  292. //
  293. int make_connection(uchar *host, uint port, uchar ip[4])
  294. {
  295. struct hostent *he;
  296. struct sockaddr_in sin;
  297. int i,sock=-1,ret;
  298. g_debug(1,"entering\n");
  299. pthread_mutex_lock(&make_connection_mutex);
  300. he=gnut_hostent_copy(gethostbyname(host));
  301. if (he==NULL) {
  302. pthread_mutex_unlock(&make_connection_mutex);
  303. return -1;
  304. }
  305. pthread_mutex_unlock(&make_connection_mutex);
  306. for (i=0,ret=-1;he->h_addr_list[i]!=NULL && ret<0;i++) {
  307. g_debug(1,"trying host %i.%i.%i.%i:%i\n",
  308. (uchar) he->h_addr_list[i][0],(uchar) he->h_addr_list[i][1],
  309. (uchar) he->h_addr_list[i][2],(uchar) he->h_addr_list[i][3],port);
  310. sock=socket(AF_INET,SOCK_STREAM,6);
  311. if (sock<0) {
  312. perror("make_connection, socket");
  313. gnut_hostent_delete(he);
  314. return sock;
  315. }
  316. sin.sin_family=AF_INET;
  317. sin.sin_port=htons(port);
  318. memcpy(&sin.sin_addr.s_addr,he->h_addr_list[i],4);
  319. ret=timed_connect(sock,(struct sockaddr *) &sin, sizeof(struct sockaddr_in),10);
  320. g_debug(5,"timed_connect returned: %i\n",ret);
  321. if (ret<0) {
  322. g_debug(1,"host bad, closing\n");
  323. close(sock);
  324. } else {
  325. break;
  326. }
  327. }
  328. if (ret<0 || he->h_addr_list[i]==NULL) {
  329. g_debug(1,"returning failure\n");
  330. gnut_hostent_delete(he);
  331. return -2;
  332. }
  333. g_debug(5,"about to copy ip from slot %i\n",i);
  334. memcpy(ip,he->h_addr_list[i],4);
  335. g_debug(4,"trying to unlock mutex\n");
  336. gnut_hostent_delete(he);
  337. g_debug(1,"returning success\n");
  338. return sock;
  339. }
  340. // int send_packet (int sock, gnutella_packet *gpa)
  341. //
  342. // sends the packet described by gpa over socket sock
  343. // return 0 on success or <0 for error
  344. //
  345. int send_packet(int sock, gnutella_packet *gpa)
  346. {
  347. int ret;
  348. int t;
  349. g_debug(3,"entering\n");
  350. ret=write(sock,(char *) &gpa->gh,sizeof(gnutella_hdr));
  351. if (ret<0) {
  352. if (gnut_lib_debug>3) perror("send_packet, write header");
  353. return ret;
  354. }
  355. memcpy(&t,gpa->gh.dlen,4);
  356. t=GUINT32_FROM_LE(t);
  357. if (t>0) {
  358. ret=write(sock,gpa->data,t);
  359. if (ret<0) {
  360. if (gnut_lib_debug>3)
  361. perror("send_packet, write data");
  362. return ret;
  363. }
  364. }
  365. g_debug(3,"returning success\n");
  366. return 23+t;
  367. }
  368. // int read_packet(int sock, gnutella_packet *gpa)
  369. //
  370. // reads a packet from the socket sock into the packet
  371. // structure of gpa.
  372. // returns 0 on success or <0 on error
  373. //
  374. int read_packet(int sock, gnutella_packet *gpa)
  375. {
  376. int ret;
  377. char *ptr;
  378. int left;
  379. uint dlen;
  380. int i;
  381. g_debug(3,"entering\n");
  382. ptr=(char *) &gpa->gh;
  383. for (left=sizeof(gnutella_hdr);left>0;) {
  384. ret=timed_read(sock,ptr,left,10);
  385. g_debug(6,"timed_read returned: %i\n",ret);
  386. if (ret==-2) return 0;
  387. if (ret==0) {
  388. return -2;
  389. } else if (ret<0) {
  390. if (errno!=EINTR) {
  391. if (gnut_lib_debug>3) perror("read_packet, header");
  392. return ret;
  393. } else ret=0;
  394. }
  395. ptr+=ret;
  396. left-=ret;
  397. }
  398. assert(left==0);
  399. memcpy(&dlen,gpa->gh.dlen,4);
  400. dlen=GUINT32_FROM_LE(dlen);
  401. while (dlen>32767 || (gpa->gh.func==129 && dlen>65536)) {
  402. // We're out of sync! I'm going to do large reads until
  403. // one returns 23, which is probably a ping packet....
  404. g_debug(2,"out of sync! func=%i dlen=%i\n",gpa->gh.func,dlen);
  405. ptr=(char *) xmalloc(100);
  406. ret=1;
  407. i=0;
  408. while (ret>0 && ret!=23 && ret!=49) {
  409. ret=timed_read(sock,ptr,60,2);
  410. g_debug(6,"timed_read returned: %i\n",ret);
  411. if (ret==-2 || (++i>5)) {
  412. free(ptr);
  413. return 0;
  414. }
  415. }
  416. if (ret<=0) {
  417. free(ptr);
  418. return ret;
  419. }
  420. free(ptr);
  421. memcpy(&gpa->gh,ptr,23);
  422. memcpy(&dlen,gpa->gh.dlen,4);
  423. dlen=GUINT32_FROM_LE(dlen);
  424. }
  425. if (dlen>0) {
  426. gpa->data=(char *) calloc(dlen,1);
  427. ptr=gpa->data;
  428. for (left=dlen;left>0;) {
  429. ret=timed_read(sock,ptr,left,10);
  430. g_debug(6,"timed_read returned: %i\n",ret);
  431. if (ret==-2) return 0;
  432. if (ret==0) return -2;
  433. if (ret<0) {
  434. if (gnut_lib_debug>3) perror("read_packet, data");
  435. return ret;
  436. }
  437. ptr+=ret;
  438. left-=ret;
  439. }
  440. }
  441. if (dlen>3000) g_debug(2,"OVERSIZE packet! size: %i\n",dlen);
  442. g_debug(3,"returning success\n");
  443. return 23+dlen;
  444. }