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