Watt-32 tcp/ip  2.2 dev-rel.10
sockopt.c
Go to the documentation of this file.
1 
5 /* BSD sockets functionality for Watt-32 TCP/IP
6  *
7  * Copyright (c) 1997-2002 Gisle Vanem <gvanem@yahoo.no>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  * must display the following acknowledgement:
19  * This product includes software developed by Gisle Vanem
20  * Bergen, Norway.
21  *
22  * THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS''
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Version
34  *
35  * 0.5 : Dec 18, 1997 : G. Vanem - created
36  * 0.6 : Apr 07, 2000 : Added multicast options IP_ADD_MEMBERSHIP and
37  * IP_DROP_MEMBERSHIP. Vlad Erochine <vlad@paragon.ru>
38  * 0.7 : Jun 06, 2000 : Added support for SO_SNDLOWAT and SO_RCVLOWAT
39  */
40 
41 #include "socket.h"
42 
43 #if defined(USE_BSD_API)
44 
45 static int set_sol_opt (Socket *s, int opt, const void *val, unsigned len);
46 static int set_raw_opt (Socket *s, int opt, const void *val, int len);
47 static int get_sol_opt (Socket *s, int opt, void *val, int *len);
48 static int get_raw_opt (Socket *s, int opt, void *val, int *len);
49 
50 static int set_tcp_opt (_tcp_Socket *tcp, int opt, const void *val, int len);
51 static int set_udp_opt (_udp_Socket *udp, int opt, const void *val, int len);
52 static int get_tcp_opt (_tcp_Socket *tcp, int opt, void *val, int *len);
53 static int get_udp_opt (_udp_Socket *udp, int opt, void *val, int *len);
54 
55 static int set_recv_buf (sock_type *s, DWORD size, BOOL is_tcp);
56 static int set_xmit_buf (sock_type *s, DWORD size, BOOL is_tcp);
57 static int raw_rx_buf (_raw_Socket *raw, DWORD size);
58 static int raw6_rx_buf (_raw6_Socket *raw, DWORD size);
59 static int raw_tx_buf (_raw_Socket *raw, DWORD size);
60 static int raw6_tx_buf (_raw6_Socket *raw, DWORD size);
61 static int set_tx_lowat (Socket *s, unsigned size);
62 static int set_rx_lowat (Socket *s, unsigned size);
63 static int get_tx_lowat (const Socket *s, unsigned *size);
64 static int get_rx_lowat (const Socket *s, unsigned *size);
65 
66 #if defined(USE_DEBUG)
67 static const char *sockopt_name (int level, int option);
68 #endif
69 
70 int W32_CALL setsockopt (int s, int level, int option, const void *optval, int optlen)
71 {
73  int rc;
74 
75  SOCK_DEBUGF (("\nsetsockopt:%d, %s", s, sockopt_name(level,option)));
76 
77  if (!socket)
78  {
79  if (_sock_dos_fd(s))
80  {
81  SOCK_DEBUGF ((", ENOTSOCK"));
82  SOCK_ERRNO (ENOTSOCK);
83  return (-1);
84  }
85  SOCK_DEBUGF ((", EBADF"));
86  SOCK_ERRNO (EBADF);
87  return (-1);
88  }
89 
90  VERIFY_RW (optval, optlen);
91 
92  if ((WORD)level == SOL_SOCKET)
93  rc = set_sol_opt (socket, option, optval, optlen);
94 
95 #if 0
96  else if ((WORD)level == SOL_PACKET)
97  rc = set_packet_opt (socket, option, optval, optlen);
98 #endif
99 
100  else if (level == socket->so_proto && level == IPPROTO_TCP)
101  rc = set_tcp_opt (socket->tcp_sock, option, optval, optlen);
102 
103  else if (level == socket->so_proto && level == IPPROTO_UDP)
104  rc = set_udp_opt (socket->udp_sock, option, optval, optlen);
105 
106  else if ((level == socket->so_proto && level == IPPROTO_IP) ||
107  (level == socket->so_proto && level == IPPROTO_ICMP) ||
108  socket->so_proto == IPPROTO_UDP ||
109  socket->so_proto == IPPROTO_ICMP)
110  rc = set_raw_opt (socket, option, optval, optlen);
111 
112  else
113  {
114  SOCK_ERRNO (ENOPROTOOPT);
115  rc = -1;
116  }
117 
118  if (rc < 0)
119  SOCK_DEBUGF ((", %s", short_strerror(_w32_errno)));
120 
121  return (rc);
122 }
123 
124 int W32_CALL getsockopt (int s, int level, int option, void *optval, int *optlen)
125 {
126  Socket *socket = _socklist_find (s);
127  int rc;
128 
129  SOCK_DEBUGF (("\ngetsockopt:%d, %s", s, sockopt_name(level,option)));
130 
131  if (!socket)
132  {
133  if (_sock_dos_fd(s))
134  {
135  SOCK_DEBUGF ((", ENOTSOCK"));
136  SOCK_ERRNO (ENOTSOCK);
137  return (-1);
138  }
139  SOCK_DEBUGF ((", EBADF"));
140  SOCK_ERRNO (EBADF);
141  return (-1);
142  }
143 
144  VERIFY_RW (optlen, sizeof(u_long));
145  VERIFY_RW (optval, *optlen);
146 
147  if ((WORD)level == SOL_SOCKET)
148  rc = get_sol_opt (socket, option, optval, optlen);
149 
150 #if 0
151  else if ((WORD)level == SOL_PACKET)
152  rc = get_packet_opt (socket, option, optval, optlen);
153 #endif
154 
155  else if (level == socket->so_proto && level == IPPROTO_TCP)
156  rc = get_tcp_opt (socket->tcp_sock, option, optval, optlen);
157 
158  else if (level == socket->so_proto && level == IPPROTO_UDP)
159  rc = get_udp_opt (socket->udp_sock, option, optval, optlen);
160 
161  else if ((level == socket->so_proto && level == IPPROTO_IP) ||
162  (level == socket->so_proto && level == IPPROTO_ICMP) ||
163  socket->so_proto == IPPROTO_UDP)
164  rc = get_raw_opt (socket, option, optval, optlen);
165 
166  else
167  {
168  SOCK_ERRNO (ENOPROTOOPT);
169  rc = -1;
170  }
171 
172  if (rc < 0)
173  SOCK_DEBUGF ((", %s", short_strerror(_w32_errno)));
174 
175  return (rc);
176 }
177 
178 
179 static int set_sol_opt (Socket *s, int opt, const void *val, unsigned len)
180 {
181  struct timeval *tv = (struct timeval*) val;
182  int on = *(int*) val;
183  DWORD size = (len >= 4) ? *(DWORD*)val :
184  (len >= 2) ? *(WORD*)val :
185  (len >= 1) ? *(BYTE*)val : 0U;
186  switch (opt)
187  {
188  case SO_DEBUG:
189  case SO_ACCEPTCONN:
190  if (on)
191  s->so_options |= opt;
192  else s->so_options &= ~opt;
193  SOCK_DEBUGF ((" %d", s->so_options & opt));
194  break;
195 
196  case SO_RCVTIMEO:
197  if (len != sizeof(*tv) || tv->tv_usec < 0)
198  {
199  SOCK_ERRNO (EINVAL);
200  return (-1);
201  }
202  if (tv->tv_sec == 0) /* i.e. use system default */
203  s->timeout = sock_delay;
204  else s->timeout = (DWORD)tv->tv_sec + tv->tv_usec/1000000UL;
205  SOCK_DEBUGF ((" %d", s->timeout));
206  break;
207 
208  case SO_SNDTIMEO: /* Don't think we need this */
209  break;
210 
211  /*
212  * SO_REUSEADDR enables local address reuse. E.g. used to bind
213  * multiple sockets to the same port but with different ip-addr.
214  */
215  case SO_REUSEADDR:
216  if (s->tcp_sock && s->so_proto == IPPROTO_TCP)
217  {
218  /* This is meaningless unless a local port is bound.
219  * myport is 0 before a connect() is done.
220  */
221  reuse_localport (s->tcp_sock->myport);
222  return (0);
223  }
224  if (s->udp_sock && s->so_proto == IPPROTO_UDP)
225  {
226  reuse_localport (s->udp_sock->myport);
227  return (0);
228  }
229  SOCK_ERRNO (ENOPROTOOPT);
230  return (-1);
231 
232  /*
233  * SO_REUSEPORT enables duplicate address and port bindings
234  * ie, one can bind multiple socks to the same <ip_addr.port> pair
235  */
236 /* case SO_REUSEPORT: missing in BSD? */
237  case SO_DONTROUTE:
238  case SO_BROADCAST:
239  case SO_USELOOPBACK:
240  case SO_OOBINLINE:
241  break;
242 
243  case SO_DONTLINGER:
244  s->linger_time = 0;
245  s->linger_on = 0;
246  s->tcp_sock->locflags &= ~LF_LINGER;
247  break;
248 
249  case SO_KEEPALIVE:
250  if (on)
251  s->so_options |= SO_KEEPALIVE;
252  else s->so_options &= ~SO_KEEPALIVE;
253  SOCK_DEBUGF ((" %d", s->so_options & SO_KEEPALIVE));
254  break;
255 
256  case SO_SNDLOWAT:
257  return set_tx_lowat (s, size);
258 
259  case SO_RCVLOWAT:
260  return set_rx_lowat (s, size);
261 
262  case SO_RCVBUF:
263  if (size == 0)
264  {
265  SOCK_ERRNO (EINVAL);
266  return (-1);
267  }
268  if (s->udp_sock && s->so_proto == IPPROTO_UDP)
269  return set_recv_buf ((sock_type*)s->udp_sock, size, FALSE);
270 
271  if (s->tcp_sock && s->so_proto == IPPROTO_TCP)
272  return set_recv_buf ((sock_type*)s->tcp_sock, size, TRUE);
273 
274  if (s->raw_sock)
275  return raw_rx_buf (s->raw_sock, size);
276 
277  if (s->raw6_sock)
278  return raw6_rx_buf (s->raw6_sock, size);
279 
280  SOCK_ERRNO (ENOPROTOOPT);
281  return (-1);
282 
283  case SO_SNDBUF:
284  if (size == 0)
285  {
286  SOCK_ERRNO (EINVAL);
287  return (-1);
288  }
289  if (s->udp_sock && s->so_proto == IPPROTO_UDP)
290  return set_xmit_buf ((sock_type*)s->udp_sock, size, FALSE);
291 
292  if (s->tcp_sock && s->so_proto == IPPROTO_TCP)
293  return set_xmit_buf ((sock_type*)s->tcp_sock, size, TRUE);
294 
295  if (s->raw_sock)
296  return raw_tx_buf (s->raw_sock, size);
297 
298  if (s->raw6_sock)
299  return raw6_tx_buf (s->raw6_sock, size);
300 
301  SOCK_ERRNO (ENOPROTOOPT);
302  return (-1);
303 
304  case SO_LINGER:
305  {
306  struct linger *linger = (struct linger*) val;
307 
308  if (len < sizeof(*linger))
309  {
310  SOCK_ERRNO (EINVAL);
311  return (-1);
312  }
313 
314  if (s->so_type != SOCK_STREAM || !s->tcp_sock)
315  {
316  SOCK_ERRNO (ENOPROTOOPT);
317  return (-1);
318  }
319 
320  if (linger->l_onoff == 0 && linger->l_linger == 0)
321  {
322  s->linger_time = 0;
323  s->linger_on = 0;
324  s->tcp_sock->locflags &= ~LF_LINGER;
325  }
326  else if (linger->l_onoff /* && linger->l_linger > 0 */ )
327  {
328  unsigned sec = TCP_LINGERTIME;
329 
330  if (linger->l_linger < 100 * TCP_LINGERTIME)
331  sec = linger->l_linger / 100; /* in 10ms units */
332 
333  s->linger_time = sec;
334  s->linger_on = 1;
335  s->tcp_sock->locflags |= LF_LINGER;
336  }
337  s->so_options |= SO_LINGER;
338  }
339  break;
340 
341  default:
342  SOCK_ERRNO (ENOPROTOOPT);
343  return (-1);
344  }
345  return (0);
346 }
347 
348 
349 static int get_sol_opt (Socket *s, int opt, void *val, int *len)
350 {
351  struct timeval *tv;
352  unsigned *size = (unsigned*)val;
353 
354  switch (opt)
355  {
356  case SO_DEBUG:
357  case SO_ACCEPTCONN:
358  *(int*)val = (s->so_options & opt);
359  *len = sizeof(int);
360  break;
361 #if 0
362  case SO_OOBINLINE:
363  if (!s->tcp_sock || s->so_proto != IPPROTO_TCP)
364  {
365  SOCK_ERRNO (ENOPROTOOPT);
366  return (-1);
367  }
368  if (s->so_options & SO_OOBINLINE)
369  *(int*)val = urgent_data ((sock_type*)s->tcp_sock);
370  else *(int*)val = 0;
371  break;
372 #endif
373 
376  case SO_REUSEADDR:
377  case SO_DONTROUTE:
378  case SO_BROADCAST:
379  case SO_USELOOPBACK:
380  break;
381 
382  case SO_DONTLINGER:
383  *(int*)val = !(s->tcp_sock->locflags & LF_LINGER);
384  break;
385 
386  case SO_KEEPALIVE:
387  if (s->so_options & SO_KEEPALIVE)
388  {
389  *(int*)val = tcp_keep_idle;
390  *len = sizeof(tcp_keep_idle);
391  }
392  else
393  {
394  *(int*)val = 0;
395  *len = 0;
396  }
397  break;
398 
399  case SO_SNDLOWAT:
400  return get_tx_lowat (s, size);
401 
402  case SO_RCVLOWAT:
403  return get_rx_lowat (s, size);
404 
405  case SO_RCVBUF:
406  if (s->udp_sock && s->so_proto == IPPROTO_UDP)
407  {
408  *(int*)val = sock_rbsize ((sock_type*)s->udp_sock);
409  return (0);
410  }
411  if (s->tcp_sock && s->so_proto == IPPROTO_TCP)
412  {
413  *(int*)val = sock_rbsize ((sock_type*)s->tcp_sock);
414  return (0);
415  }
416  if (s->raw_sock)
417  {
418  *(size_t*)val = sizeof (s->raw_sock->rx_data);
419  return (0);
420  }
421  SOCK_ERRNO (ENOPROTOOPT);
422  return (-1);
423 
424  case SO_SNDBUF:
425  if (s->udp_sock && s->so_proto == IPPROTO_UDP)
426  {
427  *(unsigned*)val = 0; /* UDP doesn't have a Tx-buffer */
428  return (0);
429  }
430  if (s->tcp_sock && s->so_proto == IPPROTO_TCP)
431  {
432  *(unsigned*)val = sock_tbsize ((sock_type*)s->tcp_sock);
433  return (0);
434  }
435  if (s->raw_sock)
436  {
437  *(unsigned*)val = _mtu;
438  return (0);
439  }
440  SOCK_ERRNO (ENOPROTOOPT);
441  return (-1);
442 
443  case SO_LINGER:
444  {
445  struct linger *linger = (struct linger*) val;
446 
447  if (!len || *len < SIZEOF(*linger))
448  {
449  SOCK_ERRNO (EINVAL);
450  return (-1);
451  }
452  if (s->so_type != SOCK_STREAM || !s->tcp_sock)
453  {
454  SOCK_ERRNO (ENOPROTOOPT);
455  return (-1);
456  }
457  *len = SIZEOF(*linger);
458  linger->l_onoff = (s->tcp_sock->locflags & LF_LINGER) ? 1 : 0;
459  linger->l_linger = 100 * s->linger_time;
460  SOCK_DEBUGF ((", linger %d, %s",
461  linger->l_linger, linger->l_onoff ? "on" : "off"));
462  }
463  break;
464 
465  case SO_SNDTIMEO:
466  break;
467 
468  case SO_RCVTIMEO:
469  if (*len < SIZEOF(*tv))
470  {
471  SOCK_ERRNO (EINVAL);
472  return (-1);
473  }
474  tv = (struct timeval*)val;
475  if (s->timeout == 0)
476  {
477  tv->tv_usec = LONG_MAX;
478  tv->tv_sec = LONG_MAX;
479  }
480  else
481  {
482  tv->tv_usec = 0;
483  tv->tv_sec = s->timeout;
484  }
485  SOCK_DEBUGF ((", timeout %lu.%06ld", (DWORD)tv->tv_sec, tv->tv_usec));
486  break;
487 
488  case SO_ERROR:
489  *(int*)val = s->so_error;
490  *len = SIZEOF(s->so_error);
491  SOCK_DEBUGF ((", val %d=%s",
492  s->so_error, short_strerror(s->so_error)));
493  s->so_error = 0; /* Linux man-page states we should clear this */
494  break;
495 
496  /* case SO_STYLE: GNU libc name */
497  case SO_TYPE:
498  *(int*)val = s->so_type;
499  *len = SIZEOF(s->so_type);
500  SOCK_DEBUGF ((", type %d", s->so_type));
501  break;
502 
503  default:
504  SOCK_ERRNO (ENOPROTOOPT);
505  return (-1);
506  }
507  SOCK_ERRNO (0);
508  return (0);
509 }
510 
511 /*
512  * set/get TCP-layer options
513  */
514 static int set_tcp_opt (_tcp_Socket *tcp, int opt, const void *val, int len)
515 {
516  BOOL on = *(BOOL*)val;
517  UINT MSS;
518 
519  switch (opt)
520  {
521  case TCP_NODELAY:
522  if (on) /* disable Nagle's algorithm */
523  tcp->sockmode &= ~SOCK_MODE_NAGLE;
524  else tcp->sockmode |= SOCK_MODE_NAGLE;
525  break;
526 
527  case TCP_MAXSEG:
528  MSS = *(DWORD*)val;
529  MSS = max (MSS, MSS_MIN);
530  MSS = min (MSS, MSS_MAX);
531  tcp->max_seg = MSS;
532  break;
533 
534  case TCP_NOPUSH:
535  if (on)
536  tcp->locflags |= LF_NOPUSH;
537  else tcp->locflags &= ~LF_NOPUSH;
538  break;
539 
540  case TCP_NOOPT:
541  if (on)
542  tcp->locflags |= LF_NOOPT;
543  else tcp->locflags &= ~LF_NOOPT;
544  break;
545 
546  default:
547  SOCK_ERRNO (ENOPROTOOPT);
548  return (-1);
549  }
550  ARGSUSED (len);
551  return (0);
552 }
553 
554 static int get_tcp_opt (_tcp_Socket *tcp, int opt, void *val, int *len)
555 {
556  switch (opt)
557  {
558  case TCP_NODELAY:
559  if (tcp->sockmode & SOCK_MODE_NAGLE)
560  *(int*)val = 0;
561  else *(int*)val = TCP_NODELAY;
562  *len = SIZEOF(int);
563  break;
564 
565  case TCP_MAXSEG:
566  *(int*)val = tcp->max_seg;
567  *len = SIZEOF(int);
568  break;
569 
570  case TCP_NOPUSH:
571  *(int*)val = (tcp->locflags & LF_NOPUSH);
572  *len = SIZEOF(tcp->locflags);
573  break;
574 
575  case TCP_NOOPT:
576  *(int*)val = (tcp->locflags & LF_NOOPT);
577  *len = SIZEOF(tcp->locflags);
578  break;
579 
580  default:
581  SOCK_ERRNO (ENOPROTOOPT);
582  return (-1);
583  }
584  return (0);
585 }
586 
587 /*
588  * set/get UDP-layer options
589  */
590 static int set_udp_opt (_udp_Socket *udp, int opt, const void *val, int len)
591 {
592  ARGSUSED (udp); /* no udp option support yet */
593  ARGSUSED (opt);
594  ARGSUSED (val);
595  ARGSUSED (len);
596  SOCK_ERRNO (ENOPROTOOPT);
597  return (-1);
598 }
599 
600 
601 static int get_udp_opt (_udp_Socket *udp, int opt, void *val, int *len)
602 {
603  ARGSUSED (udp); /* no udp option support yet */
604  ARGSUSED (opt);
605  ARGSUSED (val);
606  ARGSUSED (len);
607  SOCK_ERRNO (ENOPROTOOPT);
608  return (-1);
609 }
610 
611 /*
612  * set/get IP/ICMP-layer (raw/multicast) options
613  */
614 static int set_raw_opt (Socket *s, int opt, const void *val, int len)
615 {
616 #ifdef USE_MULTICAST
617  struct ip_mreq *mc_req;
618  DWORD ip;
619 #endif
620  BOOL on = *(BOOL*)val;
621 
622  switch (opt)
623  {
624  case IP_OPTIONS:
625  if (!s->ip_opt &&
626  (s->ip_opt = SOCK_CALLOC (sizeof(*s->ip_opt))) == NULL)
627  {
628  SOCK_ERRNO (ENOMEM);
629  return (-1);
630  }
631  if (len == 0 && s->ip_opt)
632  {
633  free (s->ip_opt);
634  s->ip_opt = NULL;
635  s->ip_opt_len = 0;
636  }
637  else
638  {
639  s->ip_opt_len = min ((unsigned)len, sizeof(*s->ip_opt));
640  if (len > 0)
641  memcpy (&s->ip_opt->IP_opts[0], val, s->ip_opt_len);
642  }
643  break;
644 
645  case IP_HDRINCL:
646  if (on)
647  s->inp_flags |= INP_HDRINCL;
648  else s->inp_flags &= ~INP_HDRINCL;
649  break;
650 
651  case IP_TOS:
652  s->ip_tos = *(int*)val;
653  if (s->tcp_sock)
654  s->tcp_sock->tos = s->ip_tos;
655  else if (s->raw_sock)
656  s->raw_sock->ip.tos = s->ip_tos;
657  break;
658 
659  case IP_TTL:
660  case IP_MULTICAST_TTL:
661  s->ip_ttl = *(BYTE*)val;
662  s->ip_ttl = max (1, s->ip_ttl);
663  if (s->udp_sock)
664  s->udp_sock->ttl = s->ip_ttl;
665  else if (s->tcp_sock)
666  s->tcp_sock->ttl = s->ip_ttl;
667  else if (s->raw_sock)
668  s->raw_sock->ip.ttl = s->ip_ttl;
669  break;
670 
671  case IP_ADD_MEMBERSHIP:
672  case IP_DROP_MEMBERSHIP:
673 #ifdef USE_MULTICAST
674  _multicast_on = TRUE;
675  mc_req = (struct ip_mreq*)val;
676  if (!mc_req || len < SIZEOF(*mc_req))
677  {
678  SOCK_ERRNO (EINVAL);
679  return (-1);
680  }
681  ip = ntohl (mc_req->imr_multiaddr.s_addr);
682  if (!_ip4_is_multicast(ip))
683  {
684  SOCK_ERRNO (EINVAL);
685  return (-1);
686  }
687  if (opt == IP_ADD_MEMBERSHIP && !join_mcast_group(ip))
688  {
689  SOCK_ERRNO (ENOBUFS); /* !!correct errno? */
690  return (-1);
691  }
692  if (opt == IP_DROP_MEMBERSHIP && !leave_mcast_group(ip))
693  {
694  SOCK_ERRNO (EADDRNOTAVAIL); /* !!correct errno? */
695  return (-1);
696  }
697 #endif
698  break;
699 
700  case IP_MULTICAST_IF:
701  case IP_MULTICAST_LOOP:
702  case IP_MULTICAST_VIF:
703  _multicast_on = TRUE;
704  break;
705 
706  case IP_RECVOPTS:
707  case IP_RECVRETOPTS:
708  case IP_RECVDSTADDR:
709  case IP_RETOPTS:
710  case IP_RSVP_ON:
711  case IP_RSVP_OFF:
712  case IP_RSVP_VIF_ON:
713  case IP_RSVP_VIF_OFF:
714  case IP_PORTRANGE:
715  case IP_RECVIF:
716  break;
717 
718  default:
719  SOCK_ERRNO (ENOPROTOOPT);
720  return (-1);
721  }
722  return (0);
723 }
724 
725 static int get_raw_opt (Socket *s, int opt, void *val, int *len)
726 {
727  switch (opt)
728  {
729  case IP_OPTIONS:
730  if (s->ip_opt)
731  {
732  *len = (int)s->ip_opt_len;
733  memcpy (val, &s->ip_opt->IP_opts[0], *len);
734  }
735  else
736  {
737  memset (val, 0, *len);
738  *len = 0;
739  }
740  break;
741 
742  case IP_HDRINCL:
743  *(int*)val = (s->inp_flags & INP_HDRINCL);
744  *len = sizeof(int);
745  break;
746 
747  case IP_TOS:
748  *(int*)val = s->ip_tos;
749  *len = sizeof(int);
750  break;
751 
752  case IP_TTL:
753  case IP_MULTICAST_TTL:
754  *(BYTE*)val = s->ip_ttl;
755  *len = 1;
756  break;
757 
758  case IP_RECVOPTS:
759  case IP_RECVRETOPTS:
760  case IP_RECVDSTADDR:
761  case IP_RETOPTS:
762  case IP_RSVP_ON:
763  case IP_RSVP_OFF:
764  case IP_RSVP_VIF_ON:
765  case IP_RSVP_VIF_OFF:
766  case IP_PORTRANGE:
767  case IP_RECVIF:
768  break;
769 
770  case IP_ADD_MEMBERSHIP:
771  case IP_DROP_MEMBERSHIP:
772  case IP_MULTICAST_IF:
773  _multicast_on = TRUE;
774  break;
775 
776  case IP_MULTICAST_LOOP:
777  _multicast_on = TRUE;
778  *(BYTE*)val = 0;
779  *len = 1;
780  break;
781 
782  case IP_MULTICAST_VIF:
783  _multicast_on = TRUE;
784  break;
785 
786  default:
787  SOCK_ERRNO (ENOPROTOOPT);
788  return (-1);
789  }
790  return (0);
791 }
792 
793 /*
794  * Set receive buffer size for UDP/TCP. Since sock_setbuf() handles
795  * maxiumum 64kB, we do the same here.
796  * Maximum size accepted for TCP is '64k * (2 << TCP_MAX_WINSHIFT)' = 1MByte.
797  * Minimum size is 1 byte.
798  */
799 static int set_recv_buf (sock_type *s, DWORD size, BOOL is_tcp)
800 {
801  BYTE *buf;
802  DWORD len;
803  DWORD max = is_tcp ? MAX_TCP_RECV_BUF : MAX_UDP_RECV_BUF;
804 
805  if (s->tcp.rx_data == &s->tcp.rx_buf[0])
806  buf = NULL;
807  else buf = s->tcp.rx_data-4;
808 
809  size = min (size, max); /* 64kB/1MB */
810  buf = (BYTE*) realloc (buf, size+8);
811  if (!buf)
812  {
813  SOCK_ERRNO (ENOMEM);
814  return (-1);
815  }
816 
817  /* Copy the data to new buffer. Data might be overlapping
818  * hence using memmove(). Add front/back markers.
819  */
820  if (s->tcp.rx_datalen > 0)
821  {
822  len = min ((long)size-8, s->tcp.rx_datalen);
823  memmove (buf+4, s->tcp.rx_data, len);
824  }
825  *(DWORD*)buf = SAFETY_TCP;
826  *(DWORD*)(buf+4+size) = SAFETY_TCP;
827  s->tcp.rx_data = buf + 4;
828  s->tcp.max_rx_data = size - 1;
829 
830  if (is_tcp && size > USHRT_MAX)
831  s->tcp.tx_wscale = (BYTE) (size >> 16); /* not yet */
832 
833  SOCK_DEBUGF ((" %lu", size));
834  return (0);
835 }
836 
837 /*
838  * Set transmit buffer size for UDP/TCP.
839  * Max size accepted is 'max'.
840  * size == 0 is legal, but how should we handle that?
841  */
842 static int set_xmit_buf (sock_type *s, DWORD size, BOOL is_tcp)
843 {
844 #if 0 /* not yet */
845  BYTE *buf;
846  DWORD max = is_tcp ? MAX_TCP_SEND_BUF : MAX_UDP_SEND_BUF;
847  size_t len;
848 
849  size = min (size, max);
850  buf = realloc (s->tcp.tx_data, size);
851  if (!buf)
852  {
853  SOCK_ERRNO (ENOMEM);
854  return (-1);
855  }
856 
857  /* Copy current data to new buffer. Data might be overlapping
858  * hence using memmove(). Add front/back markers.
859  */
860  if (s->tcp.tx_datalen > 0)
861  {
862  len = min ((long)size-8, s->tcp.tx_datalen);
863  memmove (buf+4, s->tcp.tx_data, len);
864  }
865  *(DWORD*)buf = SAFETY_TCP;
866  *(DWORD*)(buf+size-4) = SAFETY_TCP;
867  s->tcp.tx_data = buf + 4;
868  s->tcp.maxdatalen = size - (4+4+1);
869  SOCK_DEBUGF ((" %lu", size));
870 #else
871  ARGSUSED (s);
872  ARGSUSED (size);
873  ARGSUSED (is_tcp);
874 #endif
875  return (0);
876 }
877 
878 /*
879  * Set receive buffer size for RAW socket
880  */
881 static int raw_rx_buf (_raw_Socket *raw, DWORD size)
882 {
884  SOCK_DEBUGF ((" %lu unsupported", size));
885  ARGSUSED (raw);
886  ARGSUSED (size);
887  return (0);
888 }
889 
890 static int raw6_rx_buf (_raw6_Socket *raw, DWORD size)
891 {
893  SOCK_DEBUGF ((" %lu unsupported", size));
894  ARGSUSED (raw);
895  ARGSUSED (size);
896  return (0);
897 }
898 
899 static int raw_tx_buf (_raw_Socket *raw, DWORD size)
900 {
902  SOCK_DEBUGF ((" %lu unsupported", size));
903  ARGSUSED (raw);
904  ARGSUSED (size);
905  return (0);
906 }
907 
908 static int raw6_tx_buf (_raw6_Socket *raw, DWORD size)
909 {
911  SOCK_DEBUGF ((" %lu unsupported", size));
912  ARGSUSED (raw);
913  ARGSUSED (size);
914  return (0);
915 }
916 
917 
918 /*
919  * Set send buffer "low water marks"; x >= 0, x < send-size.
920  */
921 static int set_tx_lowat (Socket *sock, unsigned size)
922 {
923  switch (sock->so_type)
924  {
925  case SOCK_STREAM:
926  sock->send_lowat = min (size, MAX_TCP_SEND_BUF-1);
927  break;
928  case SOCK_DGRAM:
929  sock->send_lowat = min (size, MAX_UDP_SEND_BUF-1);
930  break;
931  case SOCK_RAW:
932  sock->send_lowat = min (size, _mtu);
933  break;
934  default:
935  SOCK_ERRNO (ENOPROTOOPT);
936  return (-1);
937  }
938  return (0);
939 }
940 
941 /*
942  * Set receive buffer "low water marks"; x >= 0, x < recv-size.
943  */
944 static int set_rx_lowat (Socket *sock, unsigned size)
945 {
946  switch (sock->so_type)
947  {
948  case SOCK_STREAM:
949  if (sock->tcp_sock)
950  sock->recv_lowat = min (size, sock->tcp_sock->max_rx_data-1);
951  break;
952  case SOCK_DGRAM:
953  if (sock->udp_sock)
954  sock->recv_lowat = min (size, sock->udp_sock->max_rx_data-1);
955  break;
956  case SOCK_RAW:
957  sock->recv_lowat = min (size, sizeof(sock->raw_sock->rx_data)-1);
958  break;
959  default:
960  SOCK_ERRNO (ENOPROTOOPT);
961  return (-1);
962  }
963  return (0);
964 }
965 
966 /*
967  * Get receive/transmit buffer "low water marks"
968  */
969 static int get_tx_lowat (const Socket *sock, unsigned *size)
970 {
971  if (sock->so_type == SOCK_STREAM ||
972  sock->so_type == SOCK_DGRAM ||
973  sock->so_type == SOCK_RAW)
974  {
975  *size = sock->send_lowat;
976  return (0);
977  }
978  SOCK_ERRNO (ENOPROTOOPT);
979  return (-1);
980 }
981 
982 static int get_rx_lowat (const Socket *sock, unsigned *size)
983 {
984  if (sock->so_type == SOCK_STREAM ||
985  sock->so_type == SOCK_DGRAM ||
986  sock->so_type == SOCK_RAW)
987  {
988  *size = sock->recv_lowat;
989  return (0);
990  }
991  SOCK_ERRNO (ENOPROTOOPT);
992  return (-1);
993 }
994 
995 #if defined(USE_DEBUG)
996 /*
997  * Handle printing of option names
998  */
999 static const struct search_list sol_options[] = {
1000  { SO_DEBUG, "SO_DEBUG" },
1001  { SO_ACCEPTCONN, "SO_ACCEPTCONN" },
1002  { SO_REUSEADDR, "SO_REUSEADDR" },
1003  { SO_KEEPALIVE, "SO_KEEPALIVE" },
1004  { SO_DONTROUTE, "SO_DONTROUTE" },
1005  { SO_BROADCAST, "SO_BROADCAST" },
1006  { SO_USELOOPBACK, "SO_USELOOPBACK" },
1007  { SO_LINGER, "SO_LINGER" },
1008  { SO_OOBINLINE, "SO_OOBINLINE" },
1009  { SO_SNDBUF, "SO_SNDBUF" },
1010  { SO_RCVBUF, "SO_RCVBUF" },
1011  { SO_SNDLOWAT, "SO_SNDLOWAT" },
1012  { SO_RCVLOWAT, "SO_RCVLOWAT" },
1013  { SO_SNDTIMEO, "SO_SNDTIMEO" },
1014  { SO_RCVTIMEO, "SO_RCVTIMEO" },
1015  { SO_ERROR, "SO_ERROR" },
1016  { SO_TYPE, "SO_TYPE" }
1017  };
1018 
1019 static const struct search_list tcp_options[] = {
1020  { TCP_NODELAY, "TCP_NODELAY" },
1021  { TCP_MAXSEG, "TCP_MAXSEG" },
1022  { TCP_NOPUSH, "TCP_NOPUSH" },
1023  { TCP_NOOPT, "TCP_NOOPT" }
1024  };
1025 
1026 static const struct search_list ip_options[] = {
1027  { IP_OPTIONS, "IP_OPTIONS" },
1028  { IP_HDRINCL, "IP_HDRINCL" },
1029  { IP_TOS, "IP_TOS" },
1030  { IP_TTL, "IP_TTL" },
1031  { IP_RECVOPTS, "IP_RECVOPTS" },
1032  { IP_RECVRETOPTS, "IP_RECVRETOPTS" },
1033  { IP_RECVDSTADDR, "IP_RECVDSTADDR" },
1034  { IP_RETOPTS, "IP_RETOPTS" },
1035  { IP_MULTICAST_IF, "IP_MULTICAST_IF" },
1036  { IP_MULTICAST_TTL, "IP_MULTICAST_TTL" },
1037  { IP_MULTICAST_LOOP, "IP_MULTICAST_LOOP" },
1038  { IP_ADD_MEMBERSHIP, "IP_ADD_MEMBERSHIP" },
1039  { IP_DROP_MEMBERSHIP,"IP_DROP_MEMBERSHIP" },
1040  { IP_MULTICAST_VIF, "IP_MULTICAST_VIF" },
1041  { IP_RSVP_ON, "IP_RSVP_ON" },
1042  { IP_RSVP_OFF, "IP_RSVP_OFF" },
1043  { IP_RSVP_VIF_ON, "IP_RSVP_VIF_ON" },
1044  { IP_RSVP_VIF_OFF, "IP_RSVP_VIF_OFF" },
1045  { IP_PORTRANGE, "IP_PORTRANGE" },
1046  { IP_RECVIF, "IP_RECVIF" },
1047  { IP_FW_ADD, "IP_FW_ADD" },
1048  { IP_FW_DEL, "IP_FW_DEL" },
1049  { IP_FW_FLUSH, "IP_FW_FLUSH" },
1050  { IP_FW_ZERO, "IP_FW_ZERO" },
1051  { IP_FW_GET, "IP_FW_GET" },
1052  { IP_NAT, "IP_NAT" }
1053  };
1054 
1055 
1056 static const char *sockopt_name (int level, int option)
1057 {
1058  switch ((DWORD)level)
1059  {
1060  case SOL_SOCKET:
1061  return list_lookup (option, sol_options, DIM(sol_options));
1062 
1063  case IPPROTO_UDP:
1064  return ("udp option!?");
1065 
1066  case IPPROTO_TCP:
1067  return list_lookup (option, tcp_options, DIM(tcp_options));
1068 
1069  case IPPROTO_IP:
1070  case IPPROTO_ICMP:
1071  return list_lookup (option, ip_options, DIM(ip_options));
1072 
1073  default:
1074  return ("invalid level?");
1075  }
1076 }
1077 #endif /* USE_DEBUG */
1078 #endif /* USE_BSD_API */
static __inline int tcp_options(_tcp_Socket *s, BYTE *opt, BOOL is_syn)
Append options to output TCP header.
Definition: pctcp.c:2295
BYTE tos
TOS from IP-header.
Definition: wattcp.h:648
BYTE * tx_data
Tx data buffer (default tx_buf[])
Definition: wattcp.h:682
Definition: socket.h:137
Definition: if.h:84
UINT tx_datalen
number of bytes of data to send
Definition: wattcp.h:680
Definition: in.h:317
const char * list_lookup(DWORD type, const struct search_list *list, int num)
Search 'list' for 'type' and return it's name.
Definition: misc.c:929
BYTE rx_buf[tcp_MaxBufSize+1]
received data buffer
Definition: wattcp.h:616
Socket * _socklist_find(int s)
Returns a pointer to the Socket structure associated with socket 's'.
Definition: socket.c:1534
BOOL _sock_dos_fd(int s)
_sock_dos_fd - Return TRUE if `s' is a valid DOS/Win32 handle.
Definition: socket.c:222
Definition: ip.h:67
Definition: wtime.h:38
Definition: socket.h:127
BYTE rx_data[MAX_FRAG_SIZE]
room for 1 jumbo IP packet
Definition: wattcp.h:699
static int raw6_tx_buf(_raw6_Socket *raw, DWORD size)
Definition: sockopt.c:908
static int raw6_rx_buf(_raw6_Socket *raw, DWORD size)
Definition: sockopt.c:890
static int raw_rx_buf(_raw_Socket *raw, DWORD size)
Definition: sockopt.c:881
static int raw_tx_buf(_raw_Socket *raw, DWORD size)
Definition: sockopt.c:899
static int get_sol_opt(Socket *s, int opt, void *val, int *len)
Definition: sockopt.c:349
BYTE tx_wscale
Definition: wattcp.h:675
UINT max_seg
MSS for this connection.
Definition: wattcp.h:658
unsigned tcp_keep_idle
idle time before sending keepalive
Definition: pctcp.c:132