Statistics
| Branch: | Revision:

root / slirp / socket.c @ 1d6198c3

History | View | Annotate | Download (16.8 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
#ifdef __sun__
12
#include <sys/filio.h>
13
#endif
14
#include "qemu-common.h"
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(head, laddr, lport, faddr, fport)
29
        struct socket *head;
30
        struct in_addr laddr;
31
        u_int lport;
32
        struct in_addr faddr;
33
        u_int fport;
34
{
35
        struct socket *so;
36

    
37
        for (so = head->so_next; so != head; so = so->so_next) {
38
                if (so->so_lport == lport &&
39
                    so->so_laddr.s_addr == laddr.s_addr &&
40
                    so->so_faddr.s_addr == faddr.s_addr &&
41
                    so->so_fport == fport)
42
                   break;
43
        }
44

    
45
        if (so == head)
46
           return (struct socket *)NULL;
47
        return so;
48

    
49
}
50

    
51
/*
52
 * Create a new socket, initialise the fields
53
 * It is the responsibility of the caller to
54
 * insque() it into the correct linked-list
55
 */
56
struct socket *
57
socreate()
58
{
59
  struct socket *so;
60

    
61
  so = (struct socket *)malloc(sizeof(struct socket));
62
  if(so) {
63
    memset(so, 0, sizeof(struct socket));
64
    so->so_state = SS_NOFDREF;
65
    so->s = -1;
66
  }
67
  return(so);
68
}
69

    
70
/*
71
 * remque and free a socket, clobber cache
72
 */
73
void
74
sofree(so)
75
        struct socket *so;
76
{
77
  if (so->so_emu==EMU_RSH && so->extra) {
78
        sofree(so->extra);
79
        so->extra=NULL;
80
  }
81
  if (so == tcp_last_so)
82
    tcp_last_so = &tcb;
83
  else if (so == udp_last_so)
84
    udp_last_so = &udb;
85

    
86
  m_free(so->so_m);
87

    
88
  if(so->so_next && so->so_prev)
89
    remque(so);  /* crashes if so is not in a queue */
90

    
91
  free(so);
92
}
93

    
94
/*
95
 * Read from so's socket into sb_snd, updating all relevant sbuf fields
96
 * NOTE: This will only be called if it is select()ed for reading, so
97
 * a read() of 0 (or less) means it's disconnected
98
 */
99
int
100
soread(so)
101
        struct socket *so;
102
{
103
        int n, nn, lss, total;
104
        struct sbuf *sb = &so->so_snd;
105
        int len = sb->sb_datalen - sb->sb_cc;
106
        struct iovec iov[2];
107
        int mss = so->so_tcpcb->t_maxseg;
108

    
109
        DEBUG_CALL("soread");
110
        DEBUG_ARG("so = %lx", (long )so);
111

    
112
        /*
113
         * No need to check if there's enough room to read.
114
         * soread wouldn't have been called if there weren't
115
         */
116

    
117
        len = sb->sb_datalen - sb->sb_cc;
118

    
119
        iov[0].iov_base = sb->sb_wptr;
120
        iov[1].iov_base = NULL;
121
        iov[1].iov_len = 0;
122
        if (sb->sb_wptr < sb->sb_rptr) {
123
                iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
124
                /* Should never succeed, but... */
125
                if (iov[0].iov_len > len)
126
                   iov[0].iov_len = len;
127
                if (iov[0].iov_len > mss)
128
                   iov[0].iov_len -= iov[0].iov_len%mss;
129
                n = 1;
130
        } else {
131
                iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
132
                /* Should never succeed, but... */
133
                if (iov[0].iov_len > len) iov[0].iov_len = len;
134
                len -= iov[0].iov_len;
135
                if (len) {
136
                        iov[1].iov_base = sb->sb_data;
137
                        iov[1].iov_len = sb->sb_rptr - sb->sb_data;
138
                        if(iov[1].iov_len > len)
139
                           iov[1].iov_len = len;
140
                        total = iov[0].iov_len + iov[1].iov_len;
141
                        if (total > mss) {
142
                                lss = total%mss;
143
                                if (iov[1].iov_len > lss) {
144
                                        iov[1].iov_len -= lss;
145
                                        n = 2;
146
                                } else {
147
                                        lss -= iov[1].iov_len;
148
                                        iov[0].iov_len -= lss;
149
                                        n = 1;
150
                                }
151
                        } else
152
                                n = 2;
153
                } else {
154
                        if (iov[0].iov_len > mss)
155
                           iov[0].iov_len -= iov[0].iov_len%mss;
156
                        n = 1;
157
                }
158
        }
159

    
160
#ifdef HAVE_READV
161
        nn = readv(so->s, (struct iovec *)iov, n);
162
        DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
163
#else
164
        nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
165
#endif
166
        if (nn <= 0) {
167
                if (nn < 0 && (errno == EINTR || errno == EAGAIN))
168
                        return 0;
169
                else {
170
                        DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
171
                        sofcantrcvmore(so);
172
                        tcp_sockclosed(sototcpcb(so));
173
                        return -1;
174
                }
175
        }
176

    
177
#ifndef HAVE_READV
178
        /*
179
         * If there was no error, try and read the second time round
180
         * We read again if n = 2 (ie, there's another part of the buffer)
181
         * and we read as much as we could in the first read
182
         * We don't test for <= 0 this time, because there legitimately
183
         * might not be any more data (since the socket is non-blocking),
184
         * a close will be detected on next iteration.
185
         * A return of -1 wont (shouldn't) happen, since it didn't happen above
186
         */
187
        if (n == 2 && nn == iov[0].iov_len) {
188
            int ret;
189
            ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
190
            if (ret > 0)
191
                nn += ret;
192
        }
193

    
194
        DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
195
#endif
196

    
197
        /* Update fields */
198
        sb->sb_cc += nn;
199
        sb->sb_wptr += nn;
200
        if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
201
                sb->sb_wptr -= sb->sb_datalen;
202
        return nn;
203
}
204

    
205
/*
206
 * Get urgent data
207
 *
208
 * When the socket is created, we set it SO_OOBINLINE,
209
 * so when OOB data arrives, we soread() it and everything
210
 * in the send buffer is sent as urgent data
211
 */
212
void
213
sorecvoob(so)
214
        struct socket *so;
215
{
216
        struct tcpcb *tp = sototcpcb(so);
217

    
218
        DEBUG_CALL("sorecvoob");
219
        DEBUG_ARG("so = %lx", (long)so);
220

    
221
        /*
222
         * We take a guess at how much urgent data has arrived.
223
         * In most situations, when urgent data arrives, the next
224
         * read() should get all the urgent data.  This guess will
225
         * be wrong however if more data arrives just after the
226
         * urgent data, or the read() doesn't return all the
227
         * urgent data.
228
         */
229
        soread(so);
230
        tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
231
        tp->t_force = 1;
232
        tcp_output(tp);
233
        tp->t_force = 0;
234
}
235

    
236
/*
237
 * Send urgent data
238
 * There's a lot duplicated code here, but...
239
 */
240
int
241
sosendoob(so)
242
        struct socket *so;
243
{
244
        struct sbuf *sb = &so->so_rcv;
245
        char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
246

    
247
        int n, len;
248

    
249
        DEBUG_CALL("sosendoob");
250
        DEBUG_ARG("so = %lx", (long)so);
251
        DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
252

    
253
        if (so->so_urgc > 2048)
254
           so->so_urgc = 2048; /* XXXX */
255

    
256
        if (sb->sb_rptr < sb->sb_wptr) {
257
                /* We can send it directly */
258
                n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
259
                so->so_urgc -= n;
260

    
261
                DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
262
        } else {
263
                /*
264
                 * Since there's no sendv or sendtov like writev,
265
                 * we must copy all data to a linear buffer then
266
                 * send it all
267
                 */
268
                len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
269
                if (len > so->so_urgc) len = so->so_urgc;
270
                memcpy(buff, sb->sb_rptr, len);
271
                so->so_urgc -= len;
272
                if (so->so_urgc) {
273
                        n = sb->sb_wptr - sb->sb_data;
274
                        if (n > so->so_urgc) n = so->so_urgc;
275
                        memcpy((buff + len), sb->sb_data, n);
276
                        so->so_urgc -= n;
277
                        len += n;
278
                }
279
                n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
280
#ifdef DEBUG
281
                if (n != len)
282
                   DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
283
#endif
284
                DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
285
        }
286

    
287
        sb->sb_cc -= n;
288
        sb->sb_rptr += n;
289
        if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
290
                sb->sb_rptr -= sb->sb_datalen;
291

    
292
        return n;
293
}
294

    
295
/*
296
 * Write data from so_rcv to so's socket,
297
 * updating all sbuf field as necessary
298
 */
299
int
300
sowrite(so)
301
        struct socket *so;
302
{
303
        int  n,nn;
304
        struct sbuf *sb = &so->so_rcv;
305
        int len = sb->sb_cc;
306
        struct iovec iov[2];
307

    
308
        DEBUG_CALL("sowrite");
309
        DEBUG_ARG("so = %lx", (long)so);
310

    
311
        if (so->so_urgc) {
312
                sosendoob(so);
313
                if (sb->sb_cc == 0)
314
                        return 0;
315
        }
316

    
317
        /*
318
         * No need to check if there's something to write,
319
         * sowrite wouldn't have been called otherwise
320
         */
321

    
322
        len = sb->sb_cc;
323

    
324
        iov[0].iov_base = sb->sb_rptr;
325
        iov[1].iov_base = NULL;
326
        iov[1].iov_len = 0;
327
        if (sb->sb_rptr < sb->sb_wptr) {
328
                iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
329
                /* Should never succeed, but... */
330
                if (iov[0].iov_len > len) iov[0].iov_len = len;
331
                n = 1;
332
        } else {
333
                iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
334
                if (iov[0].iov_len > len) iov[0].iov_len = len;
335
                len -= iov[0].iov_len;
336
                if (len) {
337
                        iov[1].iov_base = sb->sb_data;
338
                        iov[1].iov_len = sb->sb_wptr - sb->sb_data;
339
                        if (iov[1].iov_len > len) iov[1].iov_len = len;
340
                        n = 2;
341
                } else
342
                        n = 1;
343
        }
344
        /* Check if there's urgent data to send, and if so, send it */
345

    
346
#ifdef HAVE_READV
347
        nn = writev(so->s, (const struct iovec *)iov, n);
348

    
349
        DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
350
#else
351
        nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0);
352
#endif
353
        /* This should never happen, but people tell me it does *shrug* */
354
        if (nn < 0 && (errno == EAGAIN || errno == EINTR))
355
                return 0;
356

    
357
        if (nn <= 0) {
358
                DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
359
                        so->so_state, errno));
360
                sofcantsendmore(so);
361
                tcp_sockclosed(sototcpcb(so));
362
                return -1;
363
        }
364

    
365
#ifndef HAVE_READV
366
        if (n == 2 && nn == iov[0].iov_len) {
367
            int ret;
368
            ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0);
369
            if (ret > 0)
370
                nn += ret;
371
        }
372
        DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
373
#endif
374

    
375
        /* Update sbuf */
376
        sb->sb_cc -= nn;
377
        sb->sb_rptr += nn;
378
        if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
379
                sb->sb_rptr -= sb->sb_datalen;
380

    
381
        /*
382
         * If in DRAIN mode, and there's no more data, set
383
         * it CANTSENDMORE
384
         */
385
        if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
386
                sofcantsendmore(so);
387

    
388
        return nn;
389
}
390

    
391
/*
392
 * recvfrom() a UDP socket
393
 */
394
void
395
sorecvfrom(so)
396
        struct socket *so;
397
{
398
        struct sockaddr_in addr;
399
        socklen_t addrlen = sizeof(struct sockaddr_in);
400

    
401
        DEBUG_CALL("sorecvfrom");
402
        DEBUG_ARG("so = %lx", (long)so);
403

    
404
        if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
405
          char buff[256];
406
          int len;
407

    
408
          len = recvfrom(so->s, buff, 256, 0,
409
                         (struct sockaddr *)&addr, &addrlen);
410
          /* XXX Check if reply is "correct"? */
411

    
412
          if(len == -1 || len == 0) {
413
            u_char code=ICMP_UNREACH_PORT;
414

    
415
            if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
416
            else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
417

    
418
            DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
419
                        errno,strerror(errno)));
420
            icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
421
          } else {
422
            icmp_reflect(so->so_m);
423
            so->so_m = 0; /* Don't m_free() it again! */
424
          }
425
          /* No need for this socket anymore, udp_detach it */
426
          udp_detach(so);
427
        } else {                                    /* A "normal" UDP packet */
428
          struct mbuf *m;
429
          int len, n;
430

    
431
          if (!(m = m_get())) return;
432
          m->m_data += IF_MAXLINKHDR;
433

    
434
          /*
435
           * XXX Shouldn't FIONREAD packets destined for port 53,
436
           * but I don't know the max packet size for DNS lookups
437
           */
438
          len = M_FREEROOM(m);
439
          /* if (so->so_fport != htons(53)) { */
440
          ioctlsocket(so->s, FIONREAD, &n);
441

    
442
          if (n > len) {
443
            n = (m->m_data - m->m_dat) + m->m_len + n + 1;
444
            m_inc(m, n);
445
            len = M_FREEROOM(m);
446
          }
447
          /* } */
448

    
449
          m->m_len = recvfrom(so->s, m->m_data, len, 0,
450
                              (struct sockaddr *)&addr, &addrlen);
451
          DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
452
                      m->m_len, errno,strerror(errno)));
453
          if(m->m_len<0) {
454
            u_char code=ICMP_UNREACH_PORT;
455

    
456
            if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
457
            else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
458

    
459
            DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
460
            icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
461
            m_free(m);
462
          } else {
463
          /*
464
           * Hack: domain name lookup will be used the most for UDP,
465
           * and since they'll only be used once there's no need
466
           * for the 4 minute (or whatever) timeout... So we time them
467
           * out much quicker (10 seconds  for now...)
468
           */
469
            if (so->so_expire) {
470
              if (so->so_fport == htons(53))
471
                so->so_expire = curtime + SO_EXPIREFAST;
472
              else
473
                so->so_expire = curtime + SO_EXPIRE;
474
            }
475

    
476
            /*                if (m->m_len == len) {
477
             *                        m_inc(m, MINCSIZE);
478
             *                        m->m_len = 0;
479
             *                }
480
             */
481

    
482
            /*
483
             * If this packet was destined for CTL_ADDR,
484
             * make it look like that's where it came from, done by udp_output
485
             */
486
            udp_output(so, m, &addr);
487
          } /* rx error */
488
        } /* if ping packet */
489
}
490

    
491
/*
492
 * sendto() a socket
493
 */
494
int
495
sosendto(so, m)
496
        struct socket *so;
497
        struct mbuf *m;
498
{
499
        int ret;
500
        struct sockaddr_in addr;
501

    
502
        DEBUG_CALL("sosendto");
503
        DEBUG_ARG("so = %lx", (long)so);
504
        DEBUG_ARG("m = %lx", (long)m);
505

    
506
        addr.sin_family = AF_INET;
507
        if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
508
          /* It's an alias */
509
          switch(ntohl(so->so_faddr.s_addr) & 0xff) {
510
          case CTL_DNS:
511
            addr.sin_addr = dns_addr;
512
            break;
513
          case CTL_ALIAS:
514
          default:
515
            addr.sin_addr = loopback_addr;
516
            break;
517
          }
518
        } else
519
          addr.sin_addr = so->so_faddr;
520
        addr.sin_port = so->so_fport;
521

    
522
        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)));
523

    
524
        /* Don't care what port we get */
525
        ret = sendto(so->s, m->m_data, m->m_len, 0,
526
                     (struct sockaddr *)&addr, sizeof (struct sockaddr));
527
        if (ret < 0)
528
                return -1;
529

    
530
        /*
531
         * Kill the socket if there's no reply in 4 minutes,
532
         * but only if it's an expirable socket
533
         */
534
        if (so->so_expire)
535
                so->so_expire = curtime + SO_EXPIRE;
536
        so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */
537
        return 0;
538
}
539

    
540
/*
541
 * XXX This should really be tcp_listen
542
 */
543
struct socket *
544
solisten(port, laddr, lport, flags)
545
        u_int port;
546
        u_int32_t laddr;
547
        u_int lport;
548
        int flags;
549
{
550
        struct sockaddr_in addr;
551
        struct socket *so;
552
        int s, opt = 1;
553
        socklen_t addrlen = sizeof(addr);
554

    
555
        DEBUG_CALL("solisten");
556
        DEBUG_ARG("port = %d", port);
557
        DEBUG_ARG("laddr = %x", laddr);
558
        DEBUG_ARG("lport = %d", lport);
559
        DEBUG_ARG("flags = %x", flags);
560

    
561
        if ((so = socreate()) == NULL) {
562
          /* free(so);      Not sofree() ??? free(NULL) == NOP */
563
          return NULL;
564
        }
565

    
566
        /* Don't tcp_attach... we don't need so_snd nor so_rcv */
567
        if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
568
                free(so);
569
                return NULL;
570
        }
571
        insque(so,&tcb);
572

    
573
        /*
574
         * SS_FACCEPTONCE sockets must time out.
575
         */
576
        if (flags & SS_FACCEPTONCE)
577
           so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
578

    
579
        so->so_state = (SS_FACCEPTCONN|flags);
580
        so->so_lport = lport; /* Kept in network format */
581
        so->so_laddr.s_addr = laddr; /* Ditto */
582

    
583
        addr.sin_family = AF_INET;
584
        addr.sin_addr.s_addr = INADDR_ANY;
585
        addr.sin_port = port;
586

    
587
        if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
588
            (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
589
            (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
590
            (listen(s,1) < 0)) {
591
                int tmperrno = errno; /* Don't clobber the real reason we failed */
592

    
593
                close(s);
594
                sofree(so);
595
                /* Restore the real errno */
596
#ifdef _WIN32
597
                WSASetLastError(tmperrno);
598
#else
599
                errno = tmperrno;
600
#endif
601
                return NULL;
602
        }
603
        setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
604

    
605
        getsockname(s,(struct sockaddr *)&addr,&addrlen);
606
        so->so_fport = addr.sin_port;
607
        if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
608
           so->so_faddr = alias_addr;
609
        else
610
           so->so_faddr = addr.sin_addr;
611

    
612
        so->s = s;
613
        return so;
614
}
615

    
616
#if 0
617
/*
618
 * Data is available in so_rcv
619
 * Just write() the data to the socket
620
 * XXX not yet...
621
 */
622
static void
623
sorwakeup(so)
624
        struct socket *so;
625
{
626
/*        sowrite(so); */
627
/*        FD_CLR(so->s,&writefds); */
628
}
629

630
/*
631
 * Data has been freed in so_snd
632
 * We have room for a read() if we want to
633
 * For now, don't read, it'll be done in the main loop
634
 */
635
static void
636
sowwakeup(so)
637
        struct socket *so;
638
{
639
        /* Nothing, yet */
640
}
641
#endif
642

    
643
/*
644
 * Various session state calls
645
 * XXX Should be #define's
646
 * The socket state stuff needs work, these often get call 2 or 3
647
 * times each when only 1 was needed
648
 */
649
void
650
soisfconnecting(so)
651
        register struct socket *so;
652
{
653
        so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
654
                          SS_FCANTSENDMORE|SS_FWDRAIN);
655
        so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
656
}
657

    
658
void
659
soisfconnected(so)
660
        register struct socket *so;
661
{
662
        so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
663
        so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
664
}
665

    
666
static void
667
sofcantrcvmore(struct socket *so)
668
{
669
        if ((so->so_state & SS_NOFDREF) == 0) {
670
                shutdown(so->s,0);
671
                if(global_writefds) {
672
                  FD_CLR(so->s,global_writefds);
673
                }
674
        }
675
        so->so_state &= ~(SS_ISFCONNECTING);
676
        if (so->so_state & SS_FCANTSENDMORE)
677
           so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */
678
        else
679
           so->so_state |= SS_FCANTRCVMORE;
680
}
681

    
682
static void
683
sofcantsendmore(struct socket *so)
684
{
685
        if ((so->so_state & SS_NOFDREF) == 0) {
686
            shutdown(so->s,1);           /* send FIN to fhost */
687
            if (global_readfds) {
688
                FD_CLR(so->s,global_readfds);
689
            }
690
            if (global_xfds) {
691
                FD_CLR(so->s,global_xfds);
692
            }
693
        }
694
        so->so_state &= ~(SS_ISFCONNECTING);
695
        if (so->so_state & SS_FCANTRCVMORE)
696
           so->so_state = SS_NOFDREF; /* as above */
697
        else
698
           so->so_state |= SS_FCANTSENDMORE;
699
}
700

    
701
void
702
soisfdisconnected(so)
703
        struct socket *so;
704
{
705
/*        so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */
706
/*        close(so->s); */
707
/*        so->so_state = SS_ISFDISCONNECTED; */
708
        /*
709
         * XXX Do nothing ... ?
710
         */
711
}
712

    
713
/*
714
 * Set write drain mode
715
 * Set CANTSENDMORE once all data has been write()n
716
 */
717
void
718
sofwdrain(so)
719
        struct socket *so;
720
{
721
        if (so->so_rcv.sb_cc)
722
                so->so_state |= SS_FWDRAIN;
723
        else
724
                sofcantsendmore(so);
725
}