/delegate9.9.13/maker/_-select.c

https://github.com/MewX/Psiphon3-for-Linux · C · 297 lines · 245 code · 26 blank · 26 comment · 57 complexity · 6e364e94d8e4d217dc03ab875b6623ea MD5 · raw file

  1. /*
  2. * @select.c: this file will be loaded in systems with select()
  3. */
  4. #include "ystring.h"
  5. #include "log.h"
  6. #include <stdio.h>
  7. #include "vsocket.h"
  8. #include "yselect.h" /* FD_SETSIZE and FD_SET(),etc. */
  9. /*void bzero(void *b, size_t length); *//* for FD_ZERO */
  10. int connRESETbypeer(){ return -1; }
  11. int connHUP(){ return -1; }
  12. int PollIn_HUP(int on){ return -1; }
  13. int file_ISSOCK(int fd);
  14. int IsConnected(int sock,const char **reason);
  15. int BrokenSocket(FL_PAR,int fd);
  16. int PollOut(int fd,int timeout)
  17. { struct timeval tv;
  18. FdSet mask;
  19. int nready;
  20. int ofd = fd;
  21. FdSet xmask;
  22. int issock;
  23. int iscon;
  24. if( fd < 0 )
  25. return -1;
  26. fd = SocketOf(fd);
  27. if( timeout == TIMEOUT_IMM ){
  28. tv.tv_sec = 0;
  29. tv.tv_usec = 0;
  30. }else
  31. if( timeout ){
  32. tv.tv_sec = timeout / 1000;
  33. tv.tv_usec = (timeout % 1000) * 1000;
  34. }
  35. FD_ZERO(&mask);
  36. FD_SET(fd,&mask);
  37. if( lWINSOCK() ){
  38. issock = file_ISSOCK(ofd);
  39. iscon = IsConnected(ofd,0);
  40. xmask = mask;
  41. }
  42. nready = select(FD_SETSIZE,NULL,&mask,NULL,timeout?&tv:NULL);
  43. if( lWINSOCK() && nready < 0 ){
  44. porting_dbg("-- %X PollOut(%d/%d/%d,%d)=%d %X/%X %X/%X %d/%d c%d/%d",
  45. TID,fd,SocketOf(ofd),ofd,timeout,nready,
  46. xp2i(&xmask),FD_ISSET(fd,&xmask),xp2i(&mask),FD_ISSET(fd,&mask),
  47. issock,file_ISSOCK(ofd),iscon,IsConnected(ofd,0));
  48. }
  49. if( nready <= 0 )
  50. return nready;
  51. return FD_ISSET(fd,&mask) ? 1 : 0;
  52. }
  53. int _gotOOB;
  54. int PollIn1(int fd,int timeout)
  55. { struct timeval tv;
  56. FdSet Rmask,Xmask;
  57. int nready;
  58. int ofd = fd;
  59. if( fd < 0 )
  60. return -1;
  61. fd = SocketOf(fd);
  62. if( timeout == TIMEOUT_IMM ){
  63. tv.tv_sec = 0;
  64. tv.tv_usec = 0;
  65. }else
  66. if( timeout ){
  67. tv.tv_sec = timeout / 1000;
  68. tv.tv_usec = (timeout % 1000) * 1000;
  69. }
  70. _gotOOB = 0;
  71. FD_ZERO(&Rmask);
  72. FD_SET(fd,&Rmask);
  73. Xmask = Rmask;
  74. nready = select(FD_SETSIZE,&Rmask,NULL,&Xmask,timeout?&tv:NULL);
  75. if( nready <= 0 )
  76. return nready;
  77. if( FD_ISSET(fd,&Xmask) )
  78. {
  79. if( BrokenSocket(FL_ARG,ofd) ){
  80. }else
  81. _gotOOB = ofd+1;
  82. }
  83. return FD_ISSET(fd,&Rmask) ? 1 : 0;
  84. }
  85. int file_ISSOCK(int fd);
  86. int getsocktype(int fd);
  87. int PollIns(int timeout,int size,int *mask,int *rmask)
  88. { struct timeval tvbuf,*tv;
  89. int fi,fd,maxfd;
  90. FdSet Rmask,Xmask;
  91. int nready,rready;
  92. if( timeout == TIMEOUT_IMM ){
  93. tv = &tvbuf;
  94. tv->tv_sec = 0;
  95. tv->tv_usec = 0;
  96. }else
  97. if( timeout ){
  98. tv = &tvbuf;
  99. tv->tv_sec = timeout / 1000;
  100. tv->tv_usec = (timeout % 1000) * 1000;
  101. }else tv = NULL;
  102. _gotOOB = 0;
  103. maxfd = -1;
  104. FD_ZERO(&Rmask);
  105. for(fi = 0; fi < size; fi++){
  106. fd = mask[fi];
  107. fd = SocketOf(fd);
  108. if( 0 <= fd ){
  109. FD_SET(fd,&Rmask);
  110. if( maxfd < fd )
  111. maxfd = fd;
  112. }
  113. rmask[fi] = 0;
  114. }
  115. Xmask = Rmask;
  116. nready = select(SELECT_WIDTH(maxfd),&Rmask,NULL,&Xmask,tv);
  117. if( nready < 0 && isWindows() ){
  118. for( fi = 0; fi < size; fi++ ){
  119. fd = mask[fi];
  120. if( SocketOf(fd) <= 0 )
  121. porting_dbg("PollIns(%d/%d) select(%d/%d) NOT SOCKET",
  122. fi,size,SocketOf(fd),fd);
  123. }
  124. }
  125. if( nready <= 0 )
  126. return nready;
  127. rready = 0;
  128. for(fi = 0; fi < size; fi++){
  129. int ofd = mask[fi];
  130. fd = mask[fi];
  131. fd = SocketOf(fd);
  132. if( 0 <= fd ){
  133. /*
  134. if( FD_ISSET(fd,&Rmask) ){
  135. */
  136. if( FD_ISSET(fd,&Rmask) || FD_ISSET(fd,&Xmask) ){
  137. if( lPOLL() )
  138. fprintf(stderr,"----[%2d/%2d]%d,%d R:%X X:%X\n",fd,ofd,
  139. file_ISSOCK(fd),getsocktype(fd),
  140. FD_ISSET(fd,&Rmask),FD_ISSET(fd,&Xmask));
  141. /* Xmask seems to be set unconditionally for regular file ... */
  142. if( FD_ISSET(fd,&Xmask) ){
  143. /*
  144. if( !file_ISSOCK(fd) ){
  145. */
  146. if( !file_ISSOCK(ofd) ){ /* 9.9.6 Win */
  147. /* Xmask is set on EOF of pipe on FreeBSD where pipe is not socket */
  148. syslog_ERROR("[%d/%d] select() detected EOF\n",fd,ofd);
  149. }else
  150. if( BrokenSocket(FL_ARG,ofd) ){
  151. /* 9.9.7 FreeBSD8 and CYGWIN */
  152. syslog_ERROR("[%d/%d] select() detected RST\n",fd,ofd);
  153. }else{
  154. _gotOOB = ofd+1;
  155. syslog_DEBUG("[%d/%d] select() detected OOB\n",fd,ofd);
  156. }
  157. if( FD_ISSET(fd,&Rmask) == 0 )
  158. syslog_ERROR("[%d/%d] OOB only\n",fd,ofd);
  159. }
  160. rready++;
  161. rmask[fi] = 1;
  162. }else rmask[fi] = 0;
  163. }else rmask[fi] = 0;
  164. }
  165. return rready;
  166. }
  167. int withOOB(int fd){
  168. FdSet Xmask;
  169. struct timeval tvbuf,*tv;
  170. int ready;
  171. if( fd < 0 ){
  172. syslog_ERROR("[%d] withOOB BAD-FD\n",fd);
  173. return 0;
  174. }
  175. fd = SocketOf(fd);
  176. tv = &tvbuf;
  177. FD_ZERO(&Xmask);
  178. FD_SET(fd,&Xmask);
  179. tv->tv_sec = 0;
  180. tv->tv_usec = 0;
  181. ready = select(SELECT_WIDTH(fd),NULL,NULL,&Xmask,tv);
  182. syslog_DEBUG("[%d] withOOB ? %d %X\n",fd,ready,FD_ISSET(fd,&Xmask));
  183. if( 0 < ready ){
  184. if( FD_ISSET(fd,&Xmask) )
  185. return 1;
  186. }
  187. return 0;
  188. }
  189. int PollInsOuts(int timeout,int nfds,int fdv[],int ev[],int rev[])
  190. { fd_set rfds,wfds,xfds;
  191. int fi,fd,ev1,ev2;
  192. int ofd;
  193. int width;
  194. struct timeval tv;
  195. struct timeval *tvp;
  196. int nready;
  197. FD_ZERO(&rfds);
  198. FD_ZERO(&wfds);
  199. FD_ZERO(&xfds);
  200. width = 0;
  201. for( fi = 0; fi < nfds; fi++ ){
  202. fd = fdv[fi];
  203. if( fd < 0 ){
  204. /* negative fd is not error but ignored in poll() */
  205. continue;
  206. }
  207. fd = SocketOf(fd);
  208. if( width < fd )
  209. width = fd;
  210. ev1 = ev[fi];
  211. if( ev1 & PS_IN ) FD_SET(fd,&rfds);
  212. if( ev1 & PS_OUT ) FD_SET(fd,&wfds);
  213. if( ev1 & PS_PRI ) FD_SET(fd,&xfds);
  214. }
  215. /*
  216. if( timeout ){
  217. tv.tv_sec = timeout / 1000;
  218. tv.tv_usec = (timeout % 1000) * 1000;
  219. }
  220. nready = select(SELECT_WIDTH(width),&rfds,&wfds,&xfds,timeout?&tv:NULL);
  221. */
  222. if( timeout == TIMEOUT_IMM ){
  223. tvp = &tv;
  224. tv.tv_sec = 0;
  225. tv.tv_usec = 0;
  226. }else
  227. if( timeout < 0 ){ /* spec. of timeout of poll() */
  228. tvp = NULL;
  229. }else{
  230. tvp = &tv;
  231. tv.tv_sec = timeout / 1000;
  232. tv.tv_usec = (timeout % 1000) * 1000;
  233. }
  234. nready = select(SELECT_WIDTH(width),&rfds,&wfds,&xfds,tvp);
  235. for( fi = 0; fi < nfds; fi++ ){
  236. fd = fdv[fi];
  237. ofd = fd;
  238. if( fd < 0 ){
  239. rev[fi] = 0;
  240. continue;
  241. }
  242. fd = SocketOf(fd);
  243. ev2 = 0;
  244. if( FD_ISSET(fd,&rfds) ) ev2 |= PS_IN;
  245. if( FD_ISSET(fd,&wfds) ) ev2 |= PS_OUT;
  246. /*
  247. if( FD_ISSET(fd,&xfds) ) ev2 |= PS_PRI;
  248. */
  249. if( FD_ISSET(fd,&xfds) ){
  250. if( isWindowsCE() ){
  251. /* without MSG_PEEK, to set PS_PRI to show disconn. */
  252. ev2 |= PS_PRI;
  253. }else
  254. if( EccEnabled() && (ev1 & PS_OUT) ){
  255. /* to detect reset in non-blocking connect() */
  256. ev2 |= PS_PRI;
  257. porting_dbg("-- PollInsOut PRI [%d/%d] %X/%X",
  258. fd,ofd,ev2,ev1);
  259. }else{
  260. char buf[1];
  261. int rcc;
  262. rcc = recv(fd,buf,1,MSG_PEEK|MSG_OOB);
  263. syslog_DEBUG("---- PollInOuts(%d)PRI OOB=%d\n",fd,rcc);
  264. if( 0 < rcc )
  265. ev2 |= PS_PRI;
  266. }
  267. }
  268. rev[fi] = ev2;
  269. }
  270. return nready;
  271. }