PageRenderTime 58ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/DE2_115_WEB_SERVER_RGMII_ENET0/Software/web_bsp/iniche/src/tcp/soselect.c

https://gitlab.com/rainbowguardians/RainbowHard
C | 465 lines | 264 code | 62 blank | 139 comment | 56 complexity | 08cc8981a0cc7c72cec95078ecb4475c MD5 | raw file
  1. /*
  2. * FILENAME: soselect.c
  3. *
  4. * Copyright 1997- 2000 By InterNiche Technologies Inc. All rights reserved
  5. *
  6. * soselect.c Sockets library select() support. This will probably
  7. * need to be modified on a per-port basis. If your sockets code does
  8. * not rely on select() calls, then you can omit this file form the
  9. * build.
  10. *
  11. *
  12. * MODULE: INET
  13. *
  14. * ROUTINES: t_select(), sock_selscan(), sock_select(),
  15. * ROUTINES: in_pcbnotify(), void (), tcp_notify(), FD_CLR(), FD_SET(),
  16. * ROUTINES: FD_ISSET(),
  17. *
  18. * PORTABLE: yes
  19. */
  20. #include "ipport.h"
  21. #include "tcpport.h"
  22. #ifdef INCLUDE_TCP /* include/exclude whole file at compile time */
  23. #ifdef SO_SELECT /* whole file can be ifdeffed out */
  24. #include "protosw.h"
  25. #include "in_pcb.h"
  26. /* Select routines in this file: */
  27. int sock_selscan(fd_set * ibits, fd_set * obits);
  28. int sock_select(long sock, int flags);
  29. #define SOREAD 1
  30. #define SOWRITE 2
  31. /* FUNCTION: t_select()
  32. *
  33. * t_select() - implement a UNIX-like socket select call. Causes the
  34. * calling process to block waiting for activity on any of a list of
  35. * sockets. Arrays of socket descriptions are passed for read, write,
  36. * and exception event. Any of these may be NULL if the event is not
  37. * of interest. A timeout is also passed, which is given in cticks
  38. * (TPS ticks per second). Returns the number of sockets which had an
  39. * event occur.
  40. *
  41. *
  42. * PARAM1: fd_set *in
  43. * PARAM2: fd_set *out
  44. * PARAM3: fd_set *ex
  45. * PARAM4: long tv
  46. *
  47. * RETURNS:
  48. */
  49. int
  50. t_select(fd_set * in, /* lists of sockets to watch */
  51. fd_set * out,
  52. fd_set * ex,
  53. long tv) /* ticks to wait */
  54. {
  55. fd_set obits[3], ibits [3];
  56. u_long tmo;
  57. int retval = 0;
  58. MEMSET(&obits, 0, sizeof(obits));
  59. MEMSET(&ibits, 0, sizeof(ibits));
  60. if (in)
  61. MEMCPY(&ibits[0], in, sizeof(fd_set));
  62. if (out)
  63. MEMCPY(&ibits[1], out, sizeof(fd_set));
  64. if (ex)
  65. MEMCPY(&ibits[2], ex, sizeof(fd_set));
  66. tmo = cticks + tv;
  67. /* if all the fd_sets are empty, just block; else do a real select() */
  68. if ((ibits[0].fd_count == 0) && (ibits[1].fd_count == 0) &&
  69. (ibits[2].fd_count == 0))
  70. {
  71. if (tv > 0) /* make sure we don't block on nothing forever */
  72. {
  73. #ifdef SUPERLOOP
  74. while (tmo > cticks)
  75. {
  76. tk_yield();
  77. }
  78. #else
  79. TK_SLEEP(tv);
  80. #endif
  81. }
  82. }
  83. else
  84. {
  85. #ifdef SOC_CHECK_ALWAYS
  86. int i, j;
  87. struct socket * so;
  88. for (i = 0; i < 3; i++)
  89. {
  90. for (j = 0; j < ibits[i].fd_count; j++)
  91. {
  92. so = LONG2SO(ibits[i].fd_array[j]);
  93. SOC_CHECK(so);
  94. }
  95. }
  96. #endif /* SOC_CHECK_ALWAYS */
  97. /* Lock the net semaphore before going into selscan. Upon
  98. * return we will either call tcp_sleep(), which unlocks the
  99. * semaphore, or fall into the unlock statement.
  100. */
  101. LOCK_NET_RESOURCE(NET_RESID);
  102. while ((retval = sock_selscan(ibits, obits)) == 0)
  103. {
  104. if (tv != -1L)
  105. {
  106. if (tmo <= cticks)
  107. break;
  108. }
  109. select_wait = 1;
  110. tcp_sleep (&select_wait);
  111. }
  112. UNLOCK_NET_RESOURCE(NET_RESID);
  113. }
  114. if (retval >= 0)
  115. {
  116. if (in)
  117. MEMCPY(in, &obits[0], sizeof(fd_set));
  118. if (out)
  119. MEMCPY(out, &obits[1], sizeof(fd_set));
  120. if (ex)
  121. MEMCPY(ex, &obits[2], sizeof(fd_set));
  122. }
  123. return retval;
  124. }
  125. /* FUNCTION: sock_selscan()
  126. *
  127. * sock_selscan() - internal non-blocking routine under t_select().
  128. * This scans the two FD lists passed for activity by calling the
  129. * subroutine sock_select() on a per-socket basis.
  130. *
  131. *
  132. * PARAM1: fd_set * ibits
  133. * PARAM2: fd_set * obits
  134. *
  135. * RETURNS:
  136. */
  137. int
  138. sock_selscan(fd_set * ibits, fd_set * obits)
  139. {
  140. fd_set *in, *out;
  141. int which;
  142. int sock;
  143. int flag = 0;
  144. int num_sel = 0;
  145. for (which = 0; which < 3; which++)
  146. {
  147. switch (which)
  148. {
  149. case 0:
  150. flag = SOREAD; break;
  151. case 1:
  152. flag = SOWRITE; break;
  153. case 2:
  154. flag = 0; break;
  155. }
  156. in = &ibits [which];
  157. out = &obits [which];
  158. for (sock = 0; sock < (int)in->fd_count; sock++)
  159. {
  160. if (sock_select (in->fd_array[sock], flag))
  161. {
  162. FD_SET(in->fd_array[sock], out);
  163. num_sel++;
  164. }
  165. }
  166. }
  167. return num_sel;
  168. }
  169. /* FUNCTION: sock_select()
  170. *
  171. * sock_select - handle the select logic for a single event on a
  172. * single socket. This is called multiple times from sock_selscan
  173. * above. Retuns 1 if socket is ready for event, 0 if not.
  174. *
  175. *
  176. * PARAM1: long sock
  177. * PARAM2: int flag
  178. *
  179. * RETURNS:
  180. */
  181. int
  182. sock_select(long sock, int flag)
  183. {
  184. struct socket * so;
  185. int ready = 0;
  186. so = LONG2SO(sock);
  187. switch (flag)
  188. {
  189. case SOREAD:
  190. /* can we read something from so? */
  191. if (so->so_rcv.sb_cc)
  192. {
  193. ready = 1;
  194. break;
  195. }
  196. if (so->so_state & SS_CANTRCVMORE)
  197. { ready = 1;
  198. break;
  199. }
  200. if (so->so_qlen) /* attach is ready */
  201. {
  202. ready = 1;
  203. break;
  204. }
  205. #ifdef TCP_ZEROCOPY
  206. /* zerocopy sockets with a callback set should wbe awakened
  207. if there is pending data which has been upcalled */
  208. if ((so->rx_upcall) && (so->so_state & SS_UPCALLED))
  209. {
  210. so->so_state &= ~SS_UPCALLED; /* clear flag */
  211. {
  212. ready = 1;
  213. break;
  214. }
  215. }
  216. #endif /* TCP_ZEROCOPY */
  217. /* fall to here if so is not ready to read */
  218. so->so_rcv.sb_flags |= SB_SEL; /* set flag for select wakeup */
  219. break;
  220. case SOWRITE:
  221. if ((sbspace(&(so)->so_snd) > 0) &&
  222. ((((so)->so_state&SS_ISCONNECTED) ||
  223. ((so)->so_proto->pr_flags&PR_CONNREQUIRED)==0) ||
  224. ((so)->so_state & SS_CANTSENDMORE)))
  225. {
  226. ready = 1;
  227. break;
  228. }
  229. sbselqueue (&so->so_snd);
  230. break;
  231. case 0:
  232. if (so->so_oobmark || (so->so_state & SS_RCVATMARK))
  233. {
  234. ready = 1;
  235. break;
  236. }
  237. if (so->so_error &&
  238. (so->so_error != EINPROGRESS) &&
  239. (so->so_error != EWOULDBLOCK))
  240. {
  241. ready = 1;
  242. break;
  243. }
  244. sbselqueue(&so->so_rcv);
  245. break;
  246. }
  247. return ready;
  248. }
  249. /* FUNCTION: in_pcbnotify()
  250. *
  251. * Pass some notification to all connections of a protocol
  252. * associated with address dst. Call the protocol specific
  253. * routine (if any) to handle each connection.
  254. *
  255. *
  256. * PARAM1: struct inpcb *head
  257. * PARAM2: struct in_addr *dst
  258. * PARAM3: int errnum
  259. * PARAM4: void (*notify
  260. *
  261. * RETURNS:
  262. */
  263. void
  264. in_pcbnotify(struct inpcb * head,
  265. struct in_addr * dst,
  266. int errnum,
  267. void (*notify) __P ((struct inpcb *)))
  268. {
  269. struct inpcb * inp, * oinp;
  270. for (inp = head->inp_next; inp != head;)
  271. {
  272. if (inp->inp_faddr.s_addr != dst->s_addr ||
  273. inp->inp_socket == 0)
  274. {
  275. inp = inp->inp_next;
  276. continue;
  277. }
  278. if (errnum)
  279. inp->inp_socket->so_error = errnum;
  280. oinp = inp;
  281. inp = inp->inp_next;
  282. if (notify)
  283. (*notify)(oinp);
  284. }
  285. }
  286. /* FUNCTION: tcp_notify()
  287. *
  288. * Notify a tcp user of an asynchronous error;
  289. * just wake up so that he can collect error status.
  290. *
  291. *
  292. * PARAM1: struct inpcb *inp
  293. *
  294. * RETURNS:
  295. */
  296. void
  297. tcp_notify(struct inpcb * inp)
  298. {
  299. tcp_wakeup(&inp->inp_socket->so_timeo);
  300. sorwakeup(inp->inp_socket);
  301. sowwakeup(inp->inp_socket);
  302. }
  303. /* the next three routines are derived from FD_XXX() macros, which is how they
  304. are traditionally implemented. */
  305. /* FUNCTION: ifd_clr()
  306. *
  307. * PARAM1: long socket
  308. * PARAM2: fd_set * file descriptor set
  309. *
  310. * RETURNS: none
  311. *
  312. * Removes the socket from the file descriptor set, and
  313. * compacts the fd_set.
  314. */
  315. void
  316. ifd_clr(long sock, fd_set *set)
  317. {
  318. u_int i;
  319. for (i = 0; i < set->fd_count ; i++)
  320. {
  321. if (set->fd_array[i] == sock)
  322. {
  323. while (i + 1 < set->fd_count)
  324. {
  325. set->fd_array[i] = set->fd_array[i + 1];
  326. i++;
  327. }
  328. set->fd_count--;
  329. return;
  330. }
  331. }
  332. #ifdef NPDEBUG
  333. dtrap(); /* socket wasn't found in array */
  334. #endif
  335. }
  336. /* FUNCTION: ifd_set()
  337. *
  338. * PARAM1: long socket
  339. * PARAM2: fd_set * file descriptor set
  340. *
  341. * RETURNS: none
  342. *
  343. * Adds the socket to the file descriptor set. dtrap() is
  344. * called if the fd_set structure is already full.
  345. */
  346. void
  347. ifd_set(long sock, fd_set *set)
  348. {
  349. if (set->fd_count < FD_SETSIZE)
  350. set->fd_array[set->fd_count++] = sock;
  351. #ifdef NPDEBUG
  352. else
  353. dtrap();
  354. #endif
  355. }
  356. /* FUNCTION: ifd_isset()
  357. *
  358. * PARAM1: long socket
  359. * PARAM2: fd_set * file descriptor set
  360. *
  361. * RETURNS: int TRUE if socket is a member of the fd_set
  362. *
  363. * Tests if a socket is a member of a file descriptor set.
  364. */
  365. int /* actually, boolean */
  366. ifd_isset(long sock, fd_set *set)
  367. {
  368. u_int i;
  369. for (i = 0; i < set->fd_count ; i++)
  370. {
  371. if (set->fd_array[i] == sock)
  372. return TRUE;
  373. }
  374. return FALSE;
  375. }
  376. /* FUNCTION: ifd_get()
  377. *
  378. * PARAM1: unsigned int file descriptor set index
  379. * PARAM2: fd_set * file descriptor set
  380. *
  381. * RETURNS: long socket or INVALID_SOCKET
  382. *
  383. * If index is less than the number of elements in the fd_set array,
  384. * returns the index_th element, otherwise returns INVALID_SOCKET.
  385. *
  386. * NOTE: This is not part of the original FD_XXX() functionality.
  387. */
  388. long
  389. ifd_get(unsigned i, fd_set *set)
  390. {
  391. if (i < set->fd_count)
  392. return set->fd_array[i];
  393. else
  394. {
  395. #ifdef NPDEBUG
  396. dtrap();
  397. #endif
  398. return INVALID_SOCKET;
  399. }
  400. }
  401. #endif /* SO_SELECT */
  402. #endif /* INCLUDE_TCP */
  403. /* end of file socket.c */