Sparse fixes: NULL use, header order, ANSI prototypes, static
[qemu] / slirp / socket.c
1 /*
2  * Copyright (c) 1995 Danny Gasparovski.
3  *
4  * Please read the file COPYRIGHT for the
5  * terms and conditions of the copyright.
6  */
7
8 #include "qemu-common.h"
9 #define WANT_SYS_IOCTL_H
10 #include <slirp.h>
11 #include "ip_icmp.h"
12 #ifdef __sun__
13 #include <sys/filio.h>
14 #endif
15
16 static void sofcantrcvmore(struct socket *so);
17 static void sofcantsendmore(struct socket *so);
18
19 #if 0
20 static void
21 so_init()
22 {
23         /* Nothing yet */
24 }
25 #endif
26
27 struct socket *
28 solookup(struct socket *head, struct in_addr laddr, u_int lport,
29          struct in_addr faddr, u_int fport)
30 {
31         struct socket *so;
32
33         for (so = head->so_next; so != head; so = so->so_next) {
34                 if (so->so_lport == lport &&
35                     so->so_laddr.s_addr == laddr.s_addr &&
36                     so->so_faddr.s_addr == faddr.s_addr &&
37                     so->so_fport == fport)
38                    break;
39         }
40
41         if (so == head)
42            return (struct socket *)NULL;
43         return so;
44
45 }
46
47 /*
48  * Create a new socket, initialise the fields
49  * It is the responsibility of the caller to
50  * insque() it into the correct linked-list
51  */
52 struct socket *
53 socreate(void)
54 {
55   struct socket *so;
56
57   so = (struct socket *)malloc(sizeof(struct socket));
58   if(so) {
59     memset(so, 0, sizeof(struct socket));
60     so->so_state = SS_NOFDREF;
61     so->s = -1;
62   }
63   return(so);
64 }
65
66 /*
67  * remque and free a socket, clobber cache
68  */
69 void
70 sofree(struct socket *so)
71 {
72   if (so->so_emu==EMU_RSH && so->extra) {
73         sofree(so->extra);
74         so->extra=NULL;
75   }
76   if (so == tcp_last_so)
77     tcp_last_so = &tcb;
78   else if (so == udp_last_so)
79     udp_last_so = &udb;
80
81   m_free(so->so_m);
82
83   if(so->so_next && so->so_prev)
84     remque(so);  /* crashes if so is not in a queue */
85
86   free(so);
87 }
88
89 size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
90 {
91         int n, lss, total;
92         struct sbuf *sb = &so->so_snd;
93         int len = sb->sb_datalen - sb->sb_cc;
94         int mss = so->so_tcpcb->t_maxseg;
95
96         DEBUG_CALL("sopreprbuf");
97         DEBUG_ARG("so = %lx", (long )so);
98
99         len = sb->sb_datalen - sb->sb_cc;
100
101         if (len <= 0)
102                 return 0;
103
104         iov[0].iov_base = sb->sb_wptr;
105         iov[1].iov_base = NULL;
106         iov[1].iov_len = 0;
107         if (sb->sb_wptr < sb->sb_rptr) {
108                 iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
109                 /* Should never succeed, but... */
110                 if (iov[0].iov_len > len)
111                    iov[0].iov_len = len;
112                 if (iov[0].iov_len > mss)
113                    iov[0].iov_len -= iov[0].iov_len%mss;
114                 n = 1;
115         } else {
116                 iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
117                 /* Should never succeed, but... */
118                 if (iov[0].iov_len > len) iov[0].iov_len = len;
119                 len -= iov[0].iov_len;
120                 if (len) {
121                         iov[1].iov_base = sb->sb_data;
122                         iov[1].iov_len = sb->sb_rptr - sb->sb_data;
123                         if(iov[1].iov_len > len)
124                            iov[1].iov_len = len;
125                         total = iov[0].iov_len + iov[1].iov_len;
126                         if (total > mss) {
127                                 lss = total%mss;
128                                 if (iov[1].iov_len > lss) {
129                                         iov[1].iov_len -= lss;
130                                         n = 2;
131                                 } else {
132                                         lss -= iov[1].iov_len;
133                                         iov[0].iov_len -= lss;
134                                         n = 1;
135                                 }
136                         } else
137                                 n = 2;
138                 } else {
139                         if (iov[0].iov_len > mss)
140                            iov[0].iov_len -= iov[0].iov_len%mss;
141                         n = 1;
142                 }
143         }
144         if (np)
145                 *np = n;
146
147         return iov[0].iov_len + (n - 1) * iov[1].iov_len;
148 }
149
150 /*
151  * Read from so's socket into sb_snd, updating all relevant sbuf fields
152  * NOTE: This will only be called if it is select()ed for reading, so
153  * a read() of 0 (or less) means it's disconnected
154  */
155 int
156 soread(struct socket *so)
157 {
158         int n, nn;
159         struct sbuf *sb = &so->so_snd;
160         struct iovec iov[2];
161
162         DEBUG_CALL("soread");
163         DEBUG_ARG("so = %lx", (long )so);
164
165         /*
166          * No need to check if there's enough room to read.
167          * soread wouldn't have been called if there weren't
168          */
169         sopreprbuf(so, iov, &n);
170
171 #ifdef HAVE_READV
172         nn = readv(so->s, (struct iovec *)iov, n);
173         DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
174 #else
175         nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
176 #endif
177         if (nn <= 0) {
178                 if (nn < 0 && (errno == EINTR || errno == EAGAIN))
179                         return 0;
180                 else {
181                         DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
182                         sofcantrcvmore(so);
183                         tcp_sockclosed(sototcpcb(so));
184                         return -1;
185                 }
186         }
187
188 #ifndef HAVE_READV
189         /*
190          * If there was no error, try and read the second time round
191          * We read again if n = 2 (ie, there's another part of the buffer)
192          * and we read as much as we could in the first read
193          * We don't test for <= 0 this time, because there legitimately
194          * might not be any more data (since the socket is non-blocking),
195          * a close will be detected on next iteration.
196          * A return of -1 wont (shouldn't) happen, since it didn't happen above
197          */
198         if (n == 2 && nn == iov[0].iov_len) {
199             int ret;
200             ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
201             if (ret > 0)
202                 nn += ret;
203         }
204
205         DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
206 #endif
207
208         /* Update fields */
209         sb->sb_cc += nn;
210         sb->sb_wptr += nn;
211         if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
212                 sb->sb_wptr -= sb->sb_datalen;
213         return nn;
214 }
215
216 int soreadbuf(struct socket *so, const char *buf, int size)
217 {
218     int n, nn, copy = size;
219         struct sbuf *sb = &so->so_snd;
220         struct iovec iov[2];
221
222         DEBUG_CALL("soreadbuf");
223         DEBUG_ARG("so = %lx", (long )so);
224
225         /*
226          * No need to check if there's enough room to read.
227          * soread wouldn't have been called if there weren't
228          */
229         if (sopreprbuf(so, iov, &n) < size)
230         goto err;
231
232     nn = MIN(iov[0].iov_len, copy);
233     memcpy(iov[0].iov_base, buf, nn);
234
235     copy -= nn;
236     buf += nn;
237
238     if (copy == 0)
239         goto done;
240
241     memcpy(iov[1].iov_base, buf, copy);
242
243 done:
244     /* Update fields */
245         sb->sb_cc += size;
246         sb->sb_wptr += size;
247         if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
248                 sb->sb_wptr -= sb->sb_datalen;
249     return size;
250 err:
251
252     sofcantrcvmore(so);
253     tcp_sockclosed(sototcpcb(so));
254     fprintf(stderr, "soreadbuf buffer to small");
255     return -1;
256 }
257
258 /*
259  * Get urgent data
260  *
261  * When the socket is created, we set it SO_OOBINLINE,
262  * so when OOB data arrives, we soread() it and everything
263  * in the send buffer is sent as urgent data
264  */
265 void
266 sorecvoob(struct socket *so)
267 {
268         struct tcpcb *tp = sototcpcb(so);
269
270         DEBUG_CALL("sorecvoob");
271         DEBUG_ARG("so = %lx", (long)so);
272
273         /*
274          * We take a guess at how much urgent data has arrived.
275          * In most situations, when urgent data arrives, the next
276          * read() should get all the urgent data.  This guess will
277          * be wrong however if more data arrives just after the
278          * urgent data, or the read() doesn't return all the
279          * urgent data.
280          */
281         soread(so);
282         tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
283         tp->t_force = 1;
284         tcp_output(tp);
285         tp->t_force = 0;
286 }
287
288 /*
289  * Send urgent data
290  * There's a lot duplicated code here, but...
291  */
292 int
293 sosendoob(struct socket *so)
294 {
295         struct sbuf *sb = &so->so_rcv;
296         char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
297
298         int n, len;
299
300         DEBUG_CALL("sosendoob");
301         DEBUG_ARG("so = %lx", (long)so);
302         DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
303
304         if (so->so_urgc > 2048)
305            so->so_urgc = 2048; /* XXXX */
306
307         if (sb->sb_rptr < sb->sb_wptr) {
308                 /* We can send it directly */
309                 n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
310                 so->so_urgc -= n;
311
312                 DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
313         } else {
314                 /*
315                  * Since there's no sendv or sendtov like writev,
316                  * we must copy all data to a linear buffer then
317                  * send it all
318                  */
319                 len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
320                 if (len > so->so_urgc) len = so->so_urgc;
321                 memcpy(buff, sb->sb_rptr, len);
322                 so->so_urgc -= len;
323                 if (so->so_urgc) {
324                         n = sb->sb_wptr - sb->sb_data;
325                         if (n > so->so_urgc) n = so->so_urgc;
326                         memcpy((buff + len), sb->sb_data, n);
327                         so->so_urgc -= n;
328                         len += n;
329                 }
330                 n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
331 #ifdef DEBUG
332                 if (n != len)
333                    DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
334 #endif
335                 DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
336         }
337
338         sb->sb_cc -= n;
339         sb->sb_rptr += n;
340         if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
341                 sb->sb_rptr -= sb->sb_datalen;
342
343         return n;
344 }
345
346 /*
347  * Write data from so_rcv to so's socket,
348  * updating all sbuf field as necessary
349  */
350 int
351 sowrite(struct socket *so)
352 {
353         int  n,nn;
354         struct sbuf *sb = &so->so_rcv;
355         int len = sb->sb_cc;
356         struct iovec iov[2];
357
358         DEBUG_CALL("sowrite");
359         DEBUG_ARG("so = %lx", (long)so);
360
361         if (so->so_urgc) {
362                 sosendoob(so);
363                 if (sb->sb_cc == 0)
364                         return 0;
365         }
366
367         /*
368          * No need to check if there's something to write,
369          * sowrite wouldn't have been called otherwise
370          */
371
372         len = sb->sb_cc;
373
374         iov[0].iov_base = sb->sb_rptr;
375         iov[1].iov_base = NULL;
376         iov[1].iov_len = 0;
377         if (sb->sb_rptr < sb->sb_wptr) {
378                 iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
379                 /* Should never succeed, but... */
380                 if (iov[0].iov_len > len) iov[0].iov_len = len;
381                 n = 1;
382         } else {
383                 iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
384                 if (iov[0].iov_len > len) iov[0].iov_len = len;
385                 len -= iov[0].iov_len;
386                 if (len) {
387                         iov[1].iov_base = sb->sb_data;
388                         iov[1].iov_len = sb->sb_wptr - sb->sb_data;
389                         if (iov[1].iov_len > len) iov[1].iov_len = len;
390                         n = 2;
391                 } else
392                         n = 1;
393         }
394         /* Check if there's urgent data to send, and if so, send it */
395
396 #ifdef HAVE_READV
397         nn = writev(so->s, (const struct iovec *)iov, n);
398
399         DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
400 #else
401         nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
402 #endif
403         /* This should never happen, but people tell me it does *shrug* */
404         if (nn < 0 && (errno == EAGAIN || errno == EINTR))
405                 return 0;
406
407         if (nn <= 0) {
408                 DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
409                         so->so_state, errno));
410                 sofcantsendmore(so);
411                 tcp_sockclosed(sototcpcb(so));
412                 return -1;
413         }
414
415 #ifndef HAVE_READV
416         if (n == 2 && nn == iov[0].iov_len) {
417             int ret;
418             ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
419             if (ret > 0)
420                 nn += ret;
421         }
422         DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
423 #endif
424
425         /* Update sbuf */
426         sb->sb_cc -= nn;
427         sb->sb_rptr += nn;
428         if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
429                 sb->sb_rptr -= sb->sb_datalen;
430
431         /*
432          * If in DRAIN mode, and there's no more data, set
433          * it CANTSENDMORE
434          */
435         if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
436                 sofcantsendmore(so);
437
438         return nn;
439 }
440
441 /*
442  * recvfrom() a UDP socket
443  */
444 void
445 sorecvfrom(struct socket *so)
446 {
447         struct sockaddr_in addr;
448         socklen_t addrlen = sizeof(struct sockaddr_in);
449
450         DEBUG_CALL("sorecvfrom");
451         DEBUG_ARG("so = %lx", (long)so);
452
453         if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
454           char buff[256];
455           int len;
456
457           len = recvfrom(so->s, buff, 256, 0,
458                          (struct sockaddr *)&addr, &addrlen);
459           /* XXX Check if reply is "correct"? */
460
461           if(len == -1 || len == 0) {
462             u_char code=ICMP_UNREACH_PORT;
463
464             if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
465             else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
466
467             DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
468                         errno,strerror(errno)));
469             icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
470           } else {
471             icmp_reflect(so->so_m);
472             so->so_m = NULL; /* Don't m_free() it again! */
473           }
474           /* No need for this socket anymore, udp_detach it */
475           udp_detach(so);
476         } else {                                /* A "normal" UDP packet */
477           struct mbuf *m;
478           int len, n;
479
480           if (!(m = m_get())) return;
481           m->m_data += IF_MAXLINKHDR;
482
483           /*
484            * XXX Shouldn't FIONREAD packets destined for port 53,
485            * but I don't know the max packet size for DNS lookups
486            */
487           len = M_FREEROOM(m);
488           /* if (so->so_fport != htons(53)) { */
489           ioctlsocket(so->s, FIONREAD, &n);
490
491           if (n > len) {
492             n = (m->m_data - m->m_dat) + m->m_len + n + 1;
493             m_inc(m, n);
494             len = M_FREEROOM(m);
495           }
496           /* } */
497
498           m->m_len = recvfrom(so->s, m->m_data, len, 0,
499                               (struct sockaddr *)&addr, &addrlen);
500           DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
501                       m->m_len, errno,strerror(errno)));
502           if(m->m_len<0) {
503             u_char code=ICMP_UNREACH_PORT;
504
505             if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
506             else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
507
508             DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
509             icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
510             m_free(m);
511           } else {
512           /*
513            * Hack: domain name lookup will be used the most for UDP,
514            * and since they'll only be used once there's no need
515            * for the 4 minute (or whatever) timeout... So we time them
516            * out much quicker (10 seconds  for now...)
517            */
518             if (so->so_expire) {
519               if (so->so_fport == htons(53))
520                 so->so_expire = curtime + SO_EXPIREFAST;
521               else
522                 so->so_expire = curtime + SO_EXPIRE;
523             }
524
525             /*          if (m->m_len == len) {
526              *                  m_inc(m, MINCSIZE);
527              *                  m->m_len = 0;
528              *          }
529              */
530
531             /*
532              * If this packet was destined for CTL_ADDR,
533              * make it look like that's where it came from, done by udp_output
534              */
535             udp_output(so, m, &addr);
536           } /* rx error */
537         } /* if ping packet */
538 }
539
540 /*
541  * sendto() a socket
542  */
543 int
544 sosendto(struct socket *so, struct mbuf *m)
545 {
546         int ret;
547         struct sockaddr_in addr;
548
549         DEBUG_CALL("sosendto");
550         DEBUG_ARG("so = %lx", (long)so);
551         DEBUG_ARG("m = %lx", (long)m);
552
553         addr.sin_family = AF_INET;
554         if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
555           /* It's an alias */
556           switch(ntohl(so->so_faddr.s_addr) & 0xff) {
557           case CTL_DNS:
558             addr.sin_addr = dns_addr;
559             break;
560           case CTL_ALIAS:
561           default:
562             addr.sin_addr = loopback_addr;
563             break;
564           }
565         } else
566           addr.sin_addr = so->so_faddr;
567         addr.sin_port = so->so_fport;
568
569         DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
570
571         /* Don't care what port we get */
572         ret = sendto(so->s, m->m_data, m->m_len, 0,
573                      (struct sockaddr *)&addr, sizeof (struct sockaddr));
574         if (ret < 0)
575                 return -1;
576
577         /*
578          * Kill the socket if there's no reply in 4 minutes,
579          * but only if it's an expirable socket
580          */
581         if (so->so_expire)
582                 so->so_expire = curtime + SO_EXPIRE;
583         so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */
584         return 0;
585 }
586
587 /*
588  * XXX This should really be tcp_listen
589  */
590 struct socket *
591 solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
592 {
593         struct sockaddr_in addr;
594         struct socket *so;
595         int s, opt = 1;
596         socklen_t addrlen = sizeof(addr);
597
598         DEBUG_CALL("solisten");
599         DEBUG_ARG("port = %d", port);
600         DEBUG_ARG("laddr = %x", laddr);
601         DEBUG_ARG("lport = %d", lport);
602         DEBUG_ARG("flags = %x", flags);
603
604         if ((so = socreate()) == NULL) {
605           /* free(so);      Not sofree() ??? free(NULL) == NOP */
606           return NULL;
607         }
608
609         /* Don't tcp_attach... we don't need so_snd nor so_rcv */
610         if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
611                 free(so);
612                 return NULL;
613         }
614         insque(so,&tcb);
615
616         /*
617          * SS_FACCEPTONCE sockets must time out.
618          */
619         if (flags & SS_FACCEPTONCE)
620            so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
621
622         so->so_state = (SS_FACCEPTCONN|flags);
623         so->so_lport = lport; /* Kept in network format */
624         so->so_laddr.s_addr = laddr; /* Ditto */
625
626         addr.sin_family = AF_INET;
627         addr.sin_addr.s_addr = INADDR_ANY;
628         addr.sin_port = port;
629
630         if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
631             (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
632             (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
633             (listen(s,1) < 0)) {
634                 int tmperrno = errno; /* Don't clobber the real reason we failed */
635
636                 close(s);
637                 sofree(so);
638                 /* Restore the real errno */
639 #ifdef _WIN32
640                 WSASetLastError(tmperrno);
641 #else
642                 errno = tmperrno;
643 #endif
644                 return NULL;
645         }
646         setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
647
648         getsockname(s,(struct sockaddr *)&addr,&addrlen);
649         so->so_fport = addr.sin_port;
650         if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
651            so->so_faddr = alias_addr;
652         else
653            so->so_faddr = addr.sin_addr;
654
655         so->s = s;
656         return so;
657 }
658
659 #if 0
660 /*
661  * Data is available in so_rcv
662  * Just write() the data to the socket
663  * XXX not yet...
664  */
665 static void
666 sorwakeup(so)
667         struct socket *so;
668 {
669 /*      sowrite(so); */
670 /*      FD_CLR(so->s,&writefds); */
671 }
672
673 /*
674  * Data has been freed in so_snd
675  * We have room for a read() if we want to
676  * For now, don't read, it'll be done in the main loop
677  */
678 static void
679 sowwakeup(so)
680         struct socket *so;
681 {
682         /* Nothing, yet */
683 }
684 #endif
685
686 /*
687  * Various session state calls
688  * XXX Should be #define's
689  * The socket state stuff needs work, these often get call 2 or 3
690  * times each when only 1 was needed
691  */
692 void
693 soisfconnecting(struct socket *so)
694 {
695         so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
696                           SS_FCANTSENDMORE|SS_FWDRAIN);
697         so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
698 }
699
700 void
701 soisfconnected(struct socket *so)
702 {
703         so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
704         so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
705 }
706
707 static void
708 sofcantrcvmore(struct socket *so)
709 {
710         if ((so->so_state & SS_NOFDREF) == 0) {
711                 shutdown(so->s,0);
712                 if(global_writefds) {
713                   FD_CLR(so->s,global_writefds);
714                 }
715         }
716         so->so_state &= ~(SS_ISFCONNECTING);
717         if (so->so_state & SS_FCANTSENDMORE)
718            so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */
719         else
720            so->so_state |= SS_FCANTRCVMORE;
721 }
722
723 static void
724 sofcantsendmore(struct socket *so)
725 {
726         if ((so->so_state & SS_NOFDREF) == 0) {
727             shutdown(so->s,1);           /* send FIN to fhost */
728             if (global_readfds) {
729                 FD_CLR(so->s,global_readfds);
730             }
731             if (global_xfds) {
732                 FD_CLR(so->s,global_xfds);
733             }
734         }
735         so->so_state &= ~(SS_ISFCONNECTING);
736         if (so->so_state & SS_FCANTRCVMORE)
737            so->so_state = SS_NOFDREF; /* as above */
738         else
739            so->so_state |= SS_FCANTSENDMORE;
740 }
741
742 void
743 soisfdisconnected(struct socket *so)
744 {
745 /*      so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */
746 /*      close(so->s); */
747 /*      so->so_state = SS_ISFDISCONNECTED; */
748         /*
749          * XXX Do nothing ... ?
750          */
751 }
752
753 /*
754  * Set write drain mode
755  * Set CANTSENDMORE once all data has been write()n
756  */
757 void
758 sofwdrain(struct socket *so)
759 {
760         if (so->so_rcv.sb_cc)
761                 so->so_state |= SS_FWDRAIN;
762         else
763                 sofcantsendmore(so);
764 }