ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/socket.c
Revision: 1.6
Committed: 2007-11-03T11:11:42Z (17 years ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +4 -1 lines
Log Message:
Update to slirp sources from QEMU 0.8.2:
- set slirp client hostname
- fix slirp redirection on systems without a useful host IP address
- separate alias_addr (10.0.2.2) from our_addr (Ed Swierk)
- fix 32+ KB packets handling (Ed Swierk)
- fix UDP broadcast translation error
- solaris port (Ben Taylor)

File Contents

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