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

/ocaml-4.00.0+beta2/otherlibs/unix/sockopt.c

#
C | 300 lines | 253 code | 33 blank | 14 comment | 14 complexity | 44c8cd52bc34146e5bd93cdaab5d7926 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0
  1. /***********************************************************************/
  2. /* */
  3. /* OCaml */
  4. /* */
  5. /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
  6. /* */
  7. /* Copyright 1996 Institut National de Recherche en Informatique et */
  8. /* en Automatique. All rights reserved. This file is distributed */
  9. /* under the terms of the GNU Library General Public License, with */
  10. /* the special exception on linking described in file ../../LICENSE. */
  11. /* */
  12. /***********************************************************************/
  13. /* $Id: sockopt.c 11156 2011-07-27 14:17:02Z doligez $ */
  14. #include <mlvalues.h>
  15. #include <memory.h>
  16. #include <alloc.h>
  17. #include <fail.h>
  18. #include "unixsupport.h"
  19. #ifdef HAS_SOCKETS
  20. #include <errno.h>
  21. #include <sys/time.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <netinet/tcp.h>
  25. #include "socketaddr.h"
  26. #ifndef SO_DEBUG
  27. #define SO_DEBUG (-1)
  28. #endif
  29. #ifndef SO_BROADCAST
  30. #define SO_BROADCAST (-1)
  31. #endif
  32. #ifndef SO_REUSEADDR
  33. #define SO_REUSEADDR (-1)
  34. #endif
  35. #ifndef SO_KEEPALIVE
  36. #define SO_KEEPALIVE (-1)
  37. #endif
  38. #ifndef SO_DONTROUTE
  39. #define SO_DONTROUTE (-1)
  40. #endif
  41. #ifndef SO_OOBINLINE
  42. #define SO_OOBINLINE (-1)
  43. #endif
  44. #ifndef SO_ACCEPTCONN
  45. #define SO_ACCEPTCONN (-1)
  46. #endif
  47. #ifndef SO_SNDBUF
  48. #define SO_SNDBUF (-1)
  49. #endif
  50. #ifndef SO_RCVBUF
  51. #define SO_RCVBUF (-1)
  52. #endif
  53. #ifndef SO_ERROR
  54. #define SO_ERROR (-1)
  55. #endif
  56. #ifndef SO_TYPE
  57. #define SO_TYPE (-1)
  58. #endif
  59. #ifndef SO_RCVLOWAT
  60. #define SO_RCVLOWAT (-1)
  61. #endif
  62. #ifndef SO_SNDLOWAT
  63. #define SO_SNDLOWAT (-1)
  64. #endif
  65. #ifndef SO_LINGER
  66. #define SO_LINGER (-1)
  67. #endif
  68. #ifndef SO_RCVTIMEO
  69. #define SO_RCVTIMEO (-1)
  70. #endif
  71. #ifndef SO_SNDTIMEO
  72. #define SO_SNDTIMEO (-1)
  73. #endif
  74. #ifndef TCP_NODELAY
  75. #define TCP_NODELAY (-1)
  76. #endif
  77. #ifndef SO_ERROR
  78. #define SO_ERROR (-1)
  79. #endif
  80. #ifndef IPPROTO_IPV6
  81. #define IPPROTO_IPV6 (-1)
  82. #endif
  83. #ifndef IPV6_V6ONLY
  84. #define IPV6_V6ONLY (-1)
  85. #endif
  86. enum option_type {
  87. TYPE_BOOL = 0,
  88. TYPE_INT = 1,
  89. TYPE_LINGER = 2,
  90. TYPE_TIMEVAL = 3,
  91. TYPE_UNIX_ERROR = 4
  92. };
  93. struct socket_option {
  94. int level;
  95. int option;
  96. };
  97. /* Table of options, indexed by type */
  98. static struct socket_option sockopt_bool[] = {
  99. { SOL_SOCKET, SO_DEBUG },
  100. { SOL_SOCKET, SO_BROADCAST },
  101. { SOL_SOCKET, SO_REUSEADDR },
  102. { SOL_SOCKET, SO_KEEPALIVE },
  103. { SOL_SOCKET, SO_DONTROUTE },
  104. { SOL_SOCKET, SO_OOBINLINE },
  105. { SOL_SOCKET, SO_ACCEPTCONN },
  106. { IPPROTO_TCP, TCP_NODELAY },
  107. { IPPROTO_IPV6, IPV6_V6ONLY}
  108. };
  109. static struct socket_option sockopt_int[] = {
  110. { SOL_SOCKET, SO_SNDBUF },
  111. { SOL_SOCKET, SO_RCVBUF },
  112. { SOL_SOCKET, SO_ERROR },
  113. { SOL_SOCKET, SO_TYPE },
  114. { SOL_SOCKET, SO_RCVLOWAT },
  115. { SOL_SOCKET, SO_SNDLOWAT } };
  116. static struct socket_option sockopt_linger[] = {
  117. { SOL_SOCKET, SO_LINGER }
  118. };
  119. static struct socket_option sockopt_timeval[] = {
  120. { SOL_SOCKET, SO_RCVTIMEO },
  121. { SOL_SOCKET, SO_SNDTIMEO }
  122. };
  123. static struct socket_option sockopt_unix_error[] = {
  124. { SOL_SOCKET, SO_ERROR }
  125. };
  126. static struct socket_option * sockopt_table[] = {
  127. sockopt_bool,
  128. sockopt_int,
  129. sockopt_linger,
  130. sockopt_timeval,
  131. sockopt_unix_error
  132. };
  133. static char * getsockopt_fun_name[] = {
  134. "getsockopt",
  135. "getsockopt_int",
  136. "getsockopt_optint",
  137. "getsockopt_float",
  138. "getsockopt_error"
  139. };
  140. static char * setsockopt_fun_name[] = {
  141. "setsockopt",
  142. "setsockopt_int",
  143. "setsockopt_optint",
  144. "setsockopt_float",
  145. "setsockopt_error"
  146. };
  147. union option_value {
  148. int i;
  149. struct linger lg;
  150. struct timeval tv;
  151. };
  152. CAMLexport value
  153. unix_getsockopt_aux(char * name,
  154. enum option_type ty, int level, int option,
  155. value socket)
  156. {
  157. union option_value optval;
  158. socklen_param_type optsize;
  159. switch (ty) {
  160. case TYPE_BOOL:
  161. case TYPE_INT:
  162. case TYPE_UNIX_ERROR:
  163. optsize = sizeof(optval.i); break;
  164. case TYPE_LINGER:
  165. optsize = sizeof(optval.lg); break;
  166. case TYPE_TIMEVAL:
  167. optsize = sizeof(optval.tv); break;
  168. default:
  169. unix_error(EINVAL, name, Nothing);
  170. }
  171. if (getsockopt(Int_val(socket), level, option,
  172. (void *) &optval, &optsize) == -1)
  173. uerror(name, Nothing);
  174. switch (ty) {
  175. case TYPE_BOOL:
  176. case TYPE_INT:
  177. return Val_int(optval.i);
  178. case TYPE_LINGER:
  179. if (optval.lg.l_onoff == 0) {
  180. return Val_int(0); /* None */
  181. } else {
  182. value res = alloc_small(1, 0); /* Some */
  183. Field(res, 0) = Val_int(optval.lg.l_linger);
  184. return res;
  185. }
  186. case TYPE_TIMEVAL:
  187. return copy_double((double) optval.tv.tv_sec
  188. + (double) optval.tv.tv_usec / 1e6);
  189. case TYPE_UNIX_ERROR:
  190. if (optval.i == 0) {
  191. return Val_int(0); /* None */
  192. } else {
  193. value err, res;
  194. err = unix_error_of_code(optval.i);
  195. Begin_root(err);
  196. res = alloc_small(1, 0); /* Some */
  197. Field(res, 0) = err;
  198. End_roots();
  199. return res;
  200. }
  201. default:
  202. unix_error(EINVAL, name, Nothing);
  203. }
  204. }
  205. CAMLexport value
  206. unix_setsockopt_aux(char * name,
  207. enum option_type ty, int level, int option,
  208. value socket, value val)
  209. {
  210. union option_value optval;
  211. socklen_param_type optsize;
  212. double f;
  213. switch (ty) {
  214. case TYPE_BOOL:
  215. case TYPE_INT:
  216. optsize = sizeof(optval.i);
  217. optval.i = Int_val(val);
  218. break;
  219. case TYPE_LINGER:
  220. optsize = sizeof(optval.lg);
  221. optval.lg.l_onoff = Is_block (val);
  222. if (optval.lg.l_onoff)
  223. optval.lg.l_linger = Int_val (Field (val, 0));
  224. break;
  225. case TYPE_TIMEVAL:
  226. f = Double_val(val);
  227. optsize = sizeof(optval.tv);
  228. optval.tv.tv_sec = (int) f;
  229. optval.tv.tv_usec = (int) (1e6 * (f - optval.tv.tv_sec));
  230. break;
  231. case TYPE_UNIX_ERROR:
  232. default:
  233. unix_error(EINVAL, name, Nothing);
  234. }
  235. if (setsockopt(Int_val(socket), level, option,
  236. (void *) &optval, optsize) == -1)
  237. uerror(name, Nothing);
  238. return Val_unit;
  239. }
  240. CAMLprim value unix_getsockopt(value vty, value vsocket, value voption)
  241. {
  242. enum option_type ty = Int_val(vty);
  243. struct socket_option * opt = &(sockopt_table[ty][Int_val(voption)]);
  244. return unix_getsockopt_aux(getsockopt_fun_name[ty],
  245. ty,
  246. opt->level,
  247. opt->option,
  248. vsocket);
  249. }
  250. CAMLprim value unix_setsockopt(value vty, value vsocket, value voption,
  251. value val)
  252. {
  253. enum option_type ty = Int_val(vty);
  254. struct socket_option * opt = &(sockopt_table[ty][Int_val(voption)]);
  255. return unix_setsockopt_aux(setsockopt_fun_name[ty],
  256. ty,
  257. opt->level,
  258. opt->option,
  259. vsocket,
  260. val);
  261. }
  262. #else
  263. CAMLprim value unix_getsockopt(value vty, value socket, value option)
  264. { invalid_argument("getsockopt not implemented"); }
  265. CAMLprim value unix_setsockopt(value vty, value socket, value option, value val)
  266. { invalid_argument("setsockopt not implemented"); }
  267. #endif