Statistics
| Branch: | Revision:

root / slirp / socket.c @ c94c8d64

History | View | Annotate | Download (16.1 kB)

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
#include <slirp.h>
10
#include "ip_icmp.h"
11
#include "main.h"
12

    
13
void
14
so_init()
15
{
16
        /* Nothing yet */
17
}
18

    
19

    
20
struct socket *
21
solookup(head, laddr, lport, faddr, fport)
22
        struct socket *head;
23
        struct in_addr laddr;
24
        u_int lport;
25
        struct in_addr faddr;
26
        u_int fport;
27
{
28
        struct socket *so;
29
        
30
        for (so = head->so_next; so != head; so = so->so_next) {
31
                if (so->so_lport == lport && 
32
                    so->so_laddr.s_addr == laddr.s_addr &&
33
                    so->so_faddr.s_addr == faddr.s_addr &&
34
                    so->so_fport == fport)
35
                   break;
36
        }
37
        
38
        if (so == head)
39
           return (struct socket *)NULL;
40
        return so;
41
        
42
}
43

    
44
/*
45
 * Create a new socket, initialise the fields
46
 * It is the responsibility of the caller to
47
 * insque() it into the correct linked-list
48
 */
49
struct socket *
50
socreate()
51
{
52
  struct socket *so;
53
        
54
  so = (struct socket *)malloc(sizeof(struct socket));
55
  if(so) {
56
    memset(so, 0, sizeof(struct socket));
57
    so->so_state = SS_NOFDREF;
58
    so->s = -1;
59
  }
60
  return(so);
61
}
62

    
63
/*
64
 * remque and free a socket, clobber cache
65
 */
66
void
67
sofree(so)
68
        struct socket *so;
69
{
70
  if (so->so_emu==EMU_RSH && so->extra) {
71
        sofree(so->extra);
72
        so->extra=NULL;
73
  }
74
  if (so == tcp_last_so)
75
    tcp_last_so = &tcb;
76
  else if (so == udp_last_so)
77
    udp_last_so = &udb;
78
        
79
  m_free(so->so_m);
80
        
81
  if(so->so_next && so->so_prev) 
82
    remque(so);  /* crashes if so is not in a queue */
83

    
84
  free(so);
85
}
86

    
87
/*
88
 * Read from so's socket into sb_snd, updating all relevant sbuf fields
89
 * NOTE: This will only be called if it is select()ed for reading, so
90
 * a read() of 0 (or less) means it's disconnected
91
 */
92
int
93
soread(so)
94
        struct socket *so;
95
{
96
        int n, nn, lss, total;
97
        struct sbuf *sb = &so->so_snd;
98
        int len = sb->sb_datalen - sb->sb_cc;
99
        struct iovec iov[2];
100
        int mss = so->so_tcpcb->t_maxseg;
101
        
102
        DEBUG_CALL("soread");
103
        DEBUG_ARG("so = %lx", (long )so);
104
        
105
        /* 
106
         * No need to check if there's enough room to read.
107
         * soread wouldn't have been called if there weren't
108
         */
109
        
110
        len = sb->sb_datalen - sb->sb_cc;
111
        
112
        iov[0].iov_base = sb->sb_wptr;
113
        if (sb->sb_wptr < sb->sb_rptr) {
114
                iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
115
                /* Should never succeed, but... */
116
                if (iov[0].iov_len > len)
117
                   iov[0].iov_len = len;
118
                if (iov[0].iov_len > mss)
119
                   iov[0].iov_len -= iov[0].iov_len%mss;
120
                n = 1;
121
        } else {
122
                iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
123
                /* Should never succeed, but... */
124
                if (iov[0].iov_len > len) iov[0].iov_len = len;
125
                len -= iov[0].iov_len;
126
                if (len) {
127
                        iov[1].iov_base = sb->sb_data;
128
                        iov[1].iov_len = sb->sb_rptr - sb->sb_data;
129
                        if(iov[1].iov_len > len)
130
                           iov[1].iov_len = len;
131
                        total = iov[0].iov_len + iov[1].iov_len;
132
                        if (total > mss) {
133
                                lss = total%mss;
134
                                if (iov[1].iov_len > lss) {
135
                                        iov[1].iov_len -= lss;
136
                                        n = 2;
137
                                } else {
138
                                        lss -= iov[1].iov_len;
139
                                        iov[0].iov_len -= lss;
140
                                        n = 1;
141
                                }
142
                        } else
143
                                n = 2;
144
                } else {
145
                        if (iov[0].iov_len > mss)
146
                           iov[0].iov_len -= iov[0].iov_len%mss;
147
                        n = 1;
148
                }
149
        }
150
        
151
#ifdef HAVE_READV
152
        nn = readv(so->s, (struct iovec *)iov, n);
153
        DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
154
#else
155
        nn = read(so->s, iov[0].iov_base, iov[0].iov_len);
156
#endif        
157
        if (nn <= 0) {
158
                if (nn < 0 && (errno == EINTR || errno == EAGAIN))
159
                        return 0;
160
                else {
161
                        DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
162
                        sofcantrcvmore(so);
163
                        tcp_sockclosed(sototcpcb(so));
164
                        return -1;
165
                }
166
        }
167
        
168
#ifndef HAVE_READV
169
        /*
170
         * If there was no error, try and read the second time round
171
         * We read again if n = 2 (ie, there's another part of the buffer)
172
         * and we read as much as we could in the first read
173
         * We don't test for <= 0 this time, because there legitimately
174
         * might not be any more data (since the socket is non-blocking),
175
         * a close will be detected on next iteration.
176
         * A return of -1 wont (shouldn't) happen, since it didn't happen above
177
         */
178
        if (n == 2 && nn == iov[0].iov_len)
179
           nn += read(so->s, iov[1].iov_base, iov[1].iov_len);
180
        
181
        DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
182
#endif
183
        
184
        /* Update fields */
185
        sb->sb_cc += nn;
186
        sb->sb_wptr += nn;
187
        if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
188
                sb->sb_wptr -= sb->sb_datalen;
189
        return nn;
190
}
191
        
192
/*
193
 * Get urgent data
194
 * 
195
 * When the socket is created, we set it SO_OOBINLINE,
196
 * so when OOB data arrives, we soread() it and everything
197
 * in the send buffer is sent as urgent data
198
 */
199
void
200
sorecvoob(so)
201
        struct socket *so;
202
{
203
        struct tcpcb *tp = sototcpcb(so);
204

    
205
        DEBUG_CALL("sorecvoob");
206
        DEBUG_ARG("so = %lx", (long)so);
207
        
208
        /*
209
         * We take a guess at how much urgent data has arrived.
210
         * In most situations, when urgent data arrives, the next
211
         * read() should get all the urgent data.  This guess will
212
         * be wrong however if more data arrives just after the
213
         * urgent data, or the read() doesn't return all the 
214
         * urgent data.
215
         */
216
        soread(so);
217
        tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
218
        tp->t_force = 1;
219
        tcp_output(tp);
220
        tp->t_force = 0;
221
}
222

    
223
/*
224
 * Send urgent data
225
 * There's a lot duplicated code here, but...
226
 */
227
int
228
sosendoob(so)
229
        struct socket *so;
230
{
231
        struct sbuf *sb = &so->so_rcv;
232
        char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
233
        
234
        int n, len;
235
        
236
        DEBUG_CALL("sosendoob");
237
        DEBUG_ARG("so = %lx", (long)so);
238
        DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
239
        
240
        if (so->so_urgc > 2048)
241
           so->so_urgc = 2048; /* XXXX */
242
        
243
        if (sb->sb_rptr < sb->sb_wptr) {
244
                /* We can send it directly */
245
                n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
246
                so->so_urgc -= n;
247
                
248
                DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
249
        } else {
250
                /* 
251
                 * Since there's no sendv or sendtov like writev,
252
                 * we must copy all data to a linear buffer then
253
                 * send it all
254
                 */
255
                len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
256
                if (len > so->so_urgc) len = so->so_urgc;
257
                memcpy(buff, sb->sb_rptr, len);
258
                so->so_urgc -= len;
259
                if (so->so_urgc) {
260
                        n = sb->sb_wptr - sb->sb_data;
261
                        if (n > so->so_urgc) n = so->so_urgc;
262
                        memcpy((buff + len), sb->sb_data, n);
263
                        so->so_urgc -= n;
264
                        len += n;
265
                }
266
                n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
267
#ifdef DEBUG
268
                if (n != len)
269
                   DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
270
#endif                
271
                DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
272
        }
273
        
274
        sb->sb_cc -= n;
275
        sb->sb_rptr += n;
276
        if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
277
                sb->sb_rptr -= sb->sb_datalen;
278
        
279
        return n;
280
}
281

    
282
/*
283
 * Write data from so_rcv to so's socket, 
284
 * updating all sbuf field as necessary
285
 */
286
int
287
sowrite(so)
288
        struct socket *so;
289
{
290
        int  n,nn;
291
        struct sbuf *sb = &so->so_rcv;
292
        int len = sb->sb_cc;
293
        struct iovec iov[2];
294
        
295
        DEBUG_CALL("sowrite");
296
        DEBUG_ARG("so = %lx", (long)so);
297
        
298
        if (so->so_urgc) {
299
                sosendoob(so);
300
                if (sb->sb_cc == 0)
301
                        return 0;
302
        }
303

    
304
        /*
305
         * No need to check if there's something to write,
306
         * sowrite wouldn't have been called otherwise
307
         */
308
        
309
        len = sb->sb_cc;
310
        
311
        iov[0].iov_base = sb->sb_rptr;
312
        if (sb->sb_rptr < sb->sb_wptr) {
313
                iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
314
                /* Should never succeed, but... */
315
                if (iov[0].iov_len > len) iov[0].iov_len = len;
316
                n = 1;
317
        } else {
318
                iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
319
                if (iov[0].iov_len > len) iov[0].iov_len = len;
320
                len -= iov[0].iov_len;
321
                if (len) {
322
                        iov[1].iov_base = sb->sb_data;
323
                        iov[1].iov_len = sb->sb_wptr - sb->sb_data;
324
                        if (iov[1].iov_len > len) iov[1].iov_len = len;
325
                        n = 2;
326
                } else
327
                        n = 1;
328
        }
329
        /* Check if there's urgent data to send, and if so, send it */
330

    
331
#ifdef HAVE_READV
332
        nn = writev(so->s, (const struct iovec *)iov, n);
333
        
334
        DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
335
#else
336
        nn = write(so->s, iov[0].iov_base, iov[0].iov_len);
337
#endif
338
        /* This should never happen, but people tell me it does *shrug* */
339
        if (nn < 0 && (errno == EAGAIN || errno == EINTR))
340
                return 0;
341
        
342
        if (nn <= 0) {
343
                DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
344
                        so->so_state, errno));
345
                sofcantsendmore(so);
346
                tcp_sockclosed(sototcpcb(so));
347
                return -1;
348
        }
349
        
350
#ifndef HAVE_READV
351
        if (n == 2 && nn == iov[0].iov_len)
352
           nn += write(so->s, iov[1].iov_base, iov[1].iov_len);
353
        DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
354
#endif
355
        
356
        /* Update sbuf */
357
        sb->sb_cc -= nn;
358
        sb->sb_rptr += nn;
359
        if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
360
                sb->sb_rptr -= sb->sb_datalen;
361
        
362
        /*
363
         * If in DRAIN mode, and there's no more data, set
364
         * it CANTSENDMORE
365
         */
366
        if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
367
                sofcantsendmore(so);
368
        
369
        return nn;
370
}
371

    
372
/*
373
 * recvfrom() a UDP socket
374
 */
375
void
376
sorecvfrom(so)
377
        struct socket *so;
378
{
379
        struct sockaddr_in addr;
380
        int addrlen = sizeof(struct sockaddr_in);
381
        
382
        DEBUG_CALL("sorecvfrom");
383
        DEBUG_ARG("so = %lx", (long)so);
384
        
385
        if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
386
          char buff[256];
387
          int len;
388
                
389
          len = recvfrom(so->s, buff, 256, 0, 
390
                         (struct sockaddr *)&addr, &addrlen);
391
          /* XXX Check if reply is "correct"? */
392
          
393
          if(len == -1 || len == 0) {
394
            u_char code=ICMP_UNREACH_PORT;
395

    
396
            if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
397
            else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
398
            
399
            DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
400
                        errno,strerror(errno)));
401
            icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
402
          } else {
403
            icmp_reflect(so->so_m);
404
            so->so_m = 0; /* Don't m_free() it again! */
405
          }
406
          /* No need for this socket anymore, udp_detach it */
407
          udp_detach(so);
408
        } else {                                    /* A "normal" UDP packet */
409
          struct mbuf *m;
410
          int len, n;
411

    
412
          if (!(m = m_get())) return;
413
          m->m_data += if_maxlinkhdr;
414
                
415
          /* 
416
           * XXX Shouldn't FIONREAD packets destined for port 53,
417
           * but I don't know the max packet size for DNS lookups
418
           */
419
          len = M_FREEROOM(m);
420
          /* if (so->so_fport != htons(53)) { */
421
          ioctlsocket(so->s, FIONREAD, &n);
422
          
423
          if (n > len) {
424
            n = (m->m_data - m->m_dat) + m->m_len + n + 1;
425
            m_inc(m, n);
426
            len = M_FREEROOM(m);
427
          }
428
          /* } */
429
                
430
          m->m_len = recvfrom(so->s, m->m_data, len, 0,
431
                              (struct sockaddr *)&addr, &addrlen);
432
          DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", 
433
                      m->m_len, errno,strerror(errno)));
434
          if(m->m_len<0) {
435
            u_char code=ICMP_UNREACH_PORT;
436

    
437
            if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
438
            else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
439
            
440
            DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
441
            icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
442
            m_free(m);
443
          } else {
444
          /*
445
           * Hack: domain name lookup will be used the most for UDP,
446
           * and since they'll only be used once there's no need
447
           * for the 4 minute (or whatever) timeout... So we time them
448
           * out much quicker (10 seconds  for now...)
449
           */
450
            if (so->so_expire) {
451
              if (so->so_fport == htons(53))
452
                so->so_expire = curtime + SO_EXPIREFAST;
453
              else
454
                so->so_expire = curtime + SO_EXPIRE;
455
            }
456

    
457
            /*                if (m->m_len == len) {
458
             *                        m_inc(m, MINCSIZE);
459
             *                        m->m_len = 0;
460
             *                }
461
             */
462
            
463
            /* 
464
             * If this packet was destined for CTL_ADDR,
465
             * make it look like that's where it came from, done by udp_output
466
             */
467
            udp_output(so, m, &addr);
468
          } /* rx error */
469
        } /* if ping packet */
470
}
471

    
472
/*
473
 * sendto() a socket
474
 */
475
int
476
sosendto(so, m)
477
        struct socket *so;
478
        struct mbuf *m;
479
{
480
        int ret;
481
        struct sockaddr_in addr;
482

    
483
        DEBUG_CALL("sosendto");
484
        DEBUG_ARG("so = %lx", (long)so);
485
        DEBUG_ARG("m = %lx", (long)m);
486
        
487
        addr.sin_family = AF_INET;
488
        if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
489
          /* It's an alias */
490
          switch(ntohl(so->so_faddr.s_addr) & 0xff) {
491
          case CTL_DNS:
492
            addr.sin_addr = dns_addr;
493
            break;
494
          case CTL_ALIAS:
495
          default:
496
            addr.sin_addr = loopback_addr;
497
            break;
498
          }
499
        } else
500
          addr.sin_addr = so->so_faddr;
501
        addr.sin_port = so->so_fport;
502

    
503
        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)));
504
        
505
        /* Don't care what port we get */
506
        ret = sendto(so->s, m->m_data, m->m_len, 0,
507
                     (struct sockaddr *)&addr, sizeof (struct sockaddr));
508
        if (ret < 0)
509
                return -1;
510
        
511
        /*
512
         * Kill the socket if there's no reply in 4 minutes,
513
         * but only if it's an expirable socket
514
         */
515
        if (so->so_expire)
516
                so->so_expire = curtime + SO_EXPIRE;
517
        so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */
518
        return 0;
519
}
520

    
521
/*
522
 * XXX This should really be tcp_listen
523
 */
524
struct socket *
525
solisten(port, laddr, lport, flags)
526
        u_int port;
527
        u_int32_t laddr;
528
        u_int lport;
529
        int flags;
530
{
531
        struct sockaddr_in addr;
532
        struct socket *so;
533
        int s, addrlen = sizeof(addr), opt = 1;
534

    
535
        DEBUG_CALL("solisten");
536
        DEBUG_ARG("port = %d", port);
537
        DEBUG_ARG("laddr = %x", laddr);
538
        DEBUG_ARG("lport = %d", lport);
539
        DEBUG_ARG("flags = %x", flags);
540
        
541
        if ((so = socreate()) == NULL) {
542
          /* free(so);      Not sofree() ??? free(NULL) == NOP */
543
          return NULL;
544
        }
545
        
546
        /* Don't tcp_attach... we don't need so_snd nor so_rcv */
547
        if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
548
                free(so);
549
                return NULL;
550
        }
551
        insque(so,&tcb);
552
        
553
        /* 
554
         * SS_FACCEPTONCE sockets must time out.
555
         */
556
        if (flags & SS_FACCEPTONCE)
557
           so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
558
        
559
        so->so_state = (SS_FACCEPTCONN|flags);
560
        so->so_lport = lport; /* Kept in network format */
561
        so->so_laddr.s_addr = laddr; /* Ditto */
562
        
563
        addr.sin_family = AF_INET;
564
        addr.sin_addr.s_addr = INADDR_ANY;
565
        addr.sin_port = port;
566
        
567
        if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
568
            (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
569
            (listen(s,1) < 0)) {
570
                int tmperrno = errno; /* Don't clobber the real reason we failed */
571
                
572
                close(s);
573
                sofree(so);
574
                /* Restore the real errno */
575
                errno = tmperrno;
576
                return NULL;
577
        }
578
        setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
579
        setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
580
        
581
        getsockname(s,(struct sockaddr *)&addr,&addrlen);
582
        so->so_fport = addr.sin_port;
583
        if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
584
           so->so_faddr = our_addr;
585
        else
586
           so->so_faddr = addr.sin_addr;
587

    
588
        so->s = s;
589
        return so;
590
}
591

    
592
/* 
593
 * Data is available in so_rcv
594
 * Just write() the data to the socket
595
 * XXX not yet...
596
 */
597
void
598
sorwakeup(so)
599
        struct socket *so;
600
{
601
/*        sowrite(so); */
602
/*        FD_CLR(so->s,&writefds); */
603
}
604
        
605
/*
606
 * Data has been freed in so_snd
607
 * We have room for a read() if we want to
608
 * For now, don't read, it'll be done in the main loop
609
 */
610
void
611
sowwakeup(so)
612
        struct socket *so;
613
{
614
        /* Nothing, yet */
615
}
616

    
617
/*
618
 * Various session state calls
619
 * XXX Should be #define's
620
 * The socket state stuff needs work, these often get call 2 or 3
621
 * times each when only 1 was needed
622
 */
623
void
624
soisfconnecting(so)
625
        register struct socket *so;
626
{
627
        so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
628
                          SS_FCANTSENDMORE|SS_FWDRAIN);
629
        so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
630
}
631

    
632
void
633
soisfconnected(so)
634
        register struct socket *so;
635
{
636
        so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
637
        so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
638
}
639

    
640
void
641
sofcantrcvmore(so)
642
        struct  socket *so;
643
{
644
        if ((so->so_state & SS_NOFDREF) == 0) {
645
                shutdown(so->s,0);
646
                FD_CLR(so->s, global_writefds);
647
        }
648
        so->so_state &= ~(SS_ISFCONNECTING);
649
        if (so->so_state & SS_FCANTSENDMORE)
650
           so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */
651
        else
652
           so->so_state |= SS_FCANTRCVMORE;
653
}
654

    
655
void
656
sofcantsendmore(so)
657
        struct socket *so;
658
{
659
        if ((so->so_state & SS_NOFDREF) == 0) {
660
                shutdown(so->s,1);           /* send FIN to fhost */
661
                FD_CLR(so->s, global_readfds);
662
                FD_CLR(so->s, global_xfds);
663
        }
664
        so->so_state &= ~(SS_ISFCONNECTING);
665
        if (so->so_state & SS_FCANTRCVMORE)
666
           so->so_state = SS_NOFDREF; /* as above */
667
        else
668
           so->so_state |= SS_FCANTSENDMORE;
669
}
670

    
671
void
672
soisfdisconnected(so)
673
        struct socket *so;
674
{
675
/*        so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */
676
/*        close(so->s); */
677
/*        so->so_state = SS_ISFDISCONNECTED; */
678
        /*
679
         * XXX Do nothing ... ?
680
         */
681
}
682

    
683
/*
684
 * Set write drain mode
685
 * Set CANTSENDMORE once all data has been write()n
686
 */
687
void
688
sofwdrain(so)
689
        struct socket *so;
690
{
691
        if (so->so_rcv.sb_cc)
692
                so->so_state |= SS_FWDRAIN;
693
        else
694
                sofcantsendmore(so);
695
}
696