Statistics
| Branch: | Revision:

root / slirp / socket.c @ b6dce92e

History | View | Annotate | Download (17.4 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
#include "qemu-common.h"
9
#include <slirp.h>
10
#include "ip_icmp.h"
11
#ifdef __sun__
12
#include <sys/filio.h>
13
#endif
14

    
15
static void sofcantrcvmore(struct socket *so);
16
static void sofcantsendmore(struct socket *so);
17

    
18
struct socket *
19
solookup(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
 */
43
struct socket *
44
socreate(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
  }
55
  return(so);
56
}
57

    
58
/*
59
 * remque and free a socket, clobber cache
60
 */
61
void
62
sofree(struct socket *so)
63
{
64
  Slirp *slirp = so->slirp;
65

    
66
  if (so->so_emu==EMU_RSH && so->extra) {
67
        sofree(so->extra);
68
        so->extra=NULL;
69
  }
70
  if (so == slirp->tcp_last_so) {
71
      slirp->tcp_last_so = &slirp->tcb;
72
  } else if (so == slirp->udp_last_so) {
73
      slirp->udp_last_so = &slirp->udb;
74
  }
75
  m_free(so->so_m);
76

    
77
  if(so->so_next && so->so_prev)
78
    remque(so);  /* crashes if so is not in a queue */
79

    
80
  free(so);
81
}
82

    
83
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
84
{
85
        int n, lss, total;
86
        struct sbuf *sb = &so->so_snd;
87
        int len = sb->sb_datalen - sb->sb_cc;
88
        int mss = so->so_tcpcb->t_maxseg;
89

    
90
        DEBUG_CALL("sopreprbuf");
91
        DEBUG_ARG("so = %lx", (long )so);
92

    
93
        if (len <= 0)
94
                return 0;
95

    
96
        iov[0].iov_base = sb->sb_wptr;
97
        iov[1].iov_base = NULL;
98
        iov[1].iov_len = 0;
99
        if (sb->sb_wptr < sb->sb_rptr) {
100
                iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
101
                /* Should never succeed, but... */
102
                if (iov[0].iov_len > len)
103
                   iov[0].iov_len = len;
104
                if (iov[0].iov_len > mss)
105
                   iov[0].iov_len -= iov[0].iov_len%mss;
106
                n = 1;
107
        } else {
108
                iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
109
                /* Should never succeed, but... */
110
                if (iov[0].iov_len > len) iov[0].iov_len = len;
111
                len -= iov[0].iov_len;
112
                if (len) {
113
                        iov[1].iov_base = sb->sb_data;
114
                        iov[1].iov_len = sb->sb_rptr - sb->sb_data;
115
                        if(iov[1].iov_len > len)
116
                           iov[1].iov_len = len;
117
                        total = iov[0].iov_len + iov[1].iov_len;
118
                        if (total > mss) {
119
                                lss = total%mss;
120
                                if (iov[1].iov_len > lss) {
121
                                        iov[1].iov_len -= lss;
122
                                        n = 2;
123
                                } else {
124
                                        lss -= iov[1].iov_len;
125
                                        iov[0].iov_len -= lss;
126
                                        n = 1;
127
                                }
128
                        } else
129
                                n = 2;
130
                } else {
131
                        if (iov[0].iov_len > mss)
132
                           iov[0].iov_len -= iov[0].iov_len%mss;
133
                        n = 1;
134
                }
135
        }
136
        if (np)
137
                *np = n;
138

    
139
        return iov[0].iov_len + (n - 1) * iov[1].iov_len;
140
}
141

    
142
/*
143
 * Read from so's socket into sb_snd, updating all relevant sbuf fields
144
 * NOTE: This will only be called if it is select()ed for reading, so
145
 * a read() of 0 (or less) means it's disconnected
146
 */
147
int
148
soread(struct socket *so)
149
{
150
        int n, nn;
151
        struct sbuf *sb = &so->so_snd;
152
        struct iovec iov[2];
153

    
154
        DEBUG_CALL("soread");
155
        DEBUG_ARG("so = %lx", (long )so);
156

    
157
        /*
158
         * No need to check if there's enough room to read.
159
         * soread wouldn't have been called if there weren't
160
         */
161
        sopreprbuf(so, iov, &n);
162

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

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

    
197
        DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
198
#endif
199

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

    
208
int soreadbuf(struct socket *so, const char *buf, int size)
209
{
210
    int n, nn, copy = size;
211
        struct sbuf *sb = &so->so_snd;
212
        struct iovec iov[2];
213

    
214
        DEBUG_CALL("soreadbuf");
215
        DEBUG_ARG("so = %lx", (long )so);
216

    
217
        /*
218
         * No need to check if there's enough room to read.
219
         * soread wouldn't have been called if there weren't
220
         */
221
        if (sopreprbuf(so, iov, &n) < size)
222
        goto err;
223

    
224
    nn = MIN(iov[0].iov_len, copy);
225
    memcpy(iov[0].iov_base, buf, nn);
226

    
227
    copy -= nn;
228
    buf += nn;
229

    
230
    if (copy == 0)
231
        goto done;
232

    
233
    memcpy(iov[1].iov_base, buf, copy);
234

    
235
done:
236
    /* Update fields */
237
        sb->sb_cc += size;
238
        sb->sb_wptr += size;
239
        if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
240
                sb->sb_wptr -= sb->sb_datalen;
241
    return size;
242
err:
243

    
244
    sofcantrcvmore(so);
245
    tcp_sockclosed(sototcpcb(so));
246
    fprintf(stderr, "soreadbuf buffer to small");
247
    return -1;
248
}
249

    
250
/*
251
 * Get urgent data
252
 *
253
 * When the socket is created, we set it SO_OOBINLINE,
254
 * so when OOB data arrives, we soread() it and everything
255
 * in the send buffer is sent as urgent data
256
 */
257
void
258
sorecvoob(struct socket *so)
259
{
260
        struct tcpcb *tp = sototcpcb(so);
261

    
262
        DEBUG_CALL("sorecvoob");
263
        DEBUG_ARG("so = %lx", (long)so);
264

    
265
        /*
266
         * We take a guess at how much urgent data has arrived.
267
         * In most situations, when urgent data arrives, the next
268
         * read() should get all the urgent data.  This guess will
269
         * be wrong however if more data arrives just after the
270
         * urgent data, or the read() doesn't return all the
271
         * urgent data.
272
         */
273
        soread(so);
274
        tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
275
        tp->t_force = 1;
276
        tcp_output(tp);
277
        tp->t_force = 0;
278
}
279

    
280
/*
281
 * Send urgent data
282
 * There's a lot duplicated code here, but...
283
 */
284
int
285
sosendoob(struct socket *so)
286
{
287
        struct sbuf *sb = &so->so_rcv;
288
        char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
289

    
290
        int n, len;
291

    
292
        DEBUG_CALL("sosendoob");
293
        DEBUG_ARG("so = %lx", (long)so);
294
        DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
295

    
296
        if (so->so_urgc > 2048)
297
           so->so_urgc = 2048; /* XXXX */
298

    
299
        if (sb->sb_rptr < sb->sb_wptr) {
300
                /* We can send it directly */
301
                n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
302
                so->so_urgc -= n;
303

    
304
                DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
305
        } else {
306
                /*
307
                 * Since there's no sendv or sendtov like writev,
308
                 * we must copy all data to a linear buffer then
309
                 * send it all
310
                 */
311
                len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
312
                if (len > so->so_urgc) len = so->so_urgc;
313
                memcpy(buff, sb->sb_rptr, len);
314
                so->so_urgc -= len;
315
                if (so->so_urgc) {
316
                        n = sb->sb_wptr - sb->sb_data;
317
                        if (n > so->so_urgc) n = so->so_urgc;
318
                        memcpy((buff + len), sb->sb_data, n);
319
                        so->so_urgc -= n;
320
                        len += n;
321
                }
322
                n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
323
#ifdef DEBUG
324
                if (n != len)
325
                   DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
326
#endif
327
                DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
328
        }
329

    
330
        sb->sb_cc -= n;
331
        sb->sb_rptr += n;
332
        if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
333
                sb->sb_rptr -= sb->sb_datalen;
334

    
335
        return n;
336
}
337

    
338
/*
339
 * Write data from so_rcv to so's socket,
340
 * updating all sbuf field as necessary
341
 */
342
int
343
sowrite(struct socket *so)
344
{
345
        int  n,nn;
346
        struct sbuf *sb = &so->so_rcv;
347
        int len = sb->sb_cc;
348
        struct iovec iov[2];
349

    
350
        DEBUG_CALL("sowrite");
351
        DEBUG_ARG("so = %lx", (long)so);
352

    
353
        if (so->so_urgc) {
354
                sosendoob(so);
355
                if (sb->sb_cc == 0)
356
                        return 0;
357
        }
358

    
359
        /*
360
         * No need to check if there's something to write,
361
         * sowrite wouldn't have been called otherwise
362
         */
363

    
364
        iov[0].iov_base = sb->sb_rptr;
365
        iov[1].iov_base = NULL;
366
        iov[1].iov_len = 0;
367
        if (sb->sb_rptr < sb->sb_wptr) {
368
                iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
369
                /* Should never succeed, but... */
370
                if (iov[0].iov_len > len) iov[0].iov_len = len;
371
                n = 1;
372
        } else {
373
                iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
374
                if (iov[0].iov_len > len) iov[0].iov_len = len;
375
                len -= iov[0].iov_len;
376
                if (len) {
377
                        iov[1].iov_base = sb->sb_data;
378
                        iov[1].iov_len = sb->sb_wptr - sb->sb_data;
379
                        if (iov[1].iov_len > len) iov[1].iov_len = len;
380
                        n = 2;
381
                } else
382
                        n = 1;
383
        }
384
        /* Check if there's urgent data to send, and if so, send it */
385

    
386
#ifdef HAVE_READV
387
        nn = writev(so->s, (const struct iovec *)iov, n);
388

    
389
        DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
390
#else
391
        nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
392
#endif
393
        /* This should never happen, but people tell me it does *shrug* */
394
        if (nn < 0 && (errno == EAGAIN || errno == EINTR))
395
                return 0;
396

    
397
        if (nn <= 0) {
398
                DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
399
                        so->so_state, errno));
400
                sofcantsendmore(so);
401
                tcp_sockclosed(sototcpcb(so));
402
                return -1;
403
        }
404

    
405
#ifndef HAVE_READV
406
        if (n == 2 && nn == iov[0].iov_len) {
407
            int ret;
408
            ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
409
            if (ret > 0)
410
                nn += ret;
411
        }
412
        DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
413
#endif
414

    
415
        /* Update sbuf */
416
        sb->sb_cc -= nn;
417
        sb->sb_rptr += nn;
418
        if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
419
                sb->sb_rptr -= sb->sb_datalen;
420

    
421
        /*
422
         * If in DRAIN mode, and there's no more data, set
423
         * it CANTSENDMORE
424
         */
425
        if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
426
                sofcantsendmore(so);
427

    
428
        return nn;
429
}
430

    
431
/*
432
 * recvfrom() a UDP socket
433
 */
434
void
435
sorecvfrom(struct socket *so)
436
{
437
        struct sockaddr_in addr;
438
        socklen_t addrlen = sizeof(struct sockaddr_in);
439

    
440
        DEBUG_CALL("sorecvfrom");
441
        DEBUG_ARG("so = %lx", (long)so);
442

    
443
        if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
444
          char buff[256];
445
          int len;
446

    
447
          len = recvfrom(so->s, buff, 256, 0,
448
                         (struct sockaddr *)&addr, &addrlen);
449
          /* XXX Check if reply is "correct"? */
450

    
451
          if(len == -1 || len == 0) {
452
            u_char code=ICMP_UNREACH_PORT;
453

    
454
            if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
455
            else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
456

    
457
            DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
458
                        errno,strerror(errno)));
459
            icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
460
          } else {
461
            icmp_reflect(so->so_m);
462
            so->so_m = NULL; /* Don't m_free() it again! */
463
          }
464
          /* No need for this socket anymore, udp_detach it */
465
          udp_detach(so);
466
        } else {                                    /* A "normal" UDP packet */
467
          struct mbuf *m;
468
          int len;
469
#ifdef _WIN32
470
          unsigned long n;
471
#else
472
          int n;
473
#endif
474

    
475
          m = m_get(so->slirp);
476
          if (!m) {
477
              return;
478
          }
479
          m->m_data += IF_MAXLINKHDR;
480

    
481
          /*
482
           * XXX Shouldn't FIONREAD packets destined for port 53,
483
           * but I don't know the max packet size for DNS lookups
484
           */
485
          len = M_FREEROOM(m);
486
          /* if (so->so_fport != htons(53)) { */
487
          ioctlsocket(so->s, FIONREAD, &n);
488

    
489
          if (n > len) {
490
            n = (m->m_data - m->m_dat) + m->m_len + n + 1;
491
            m_inc(m, n);
492
            len = M_FREEROOM(m);
493
          }
494
          /* } */
495

    
496
          m->m_len = recvfrom(so->s, m->m_data, len, 0,
497
                              (struct sockaddr *)&addr, &addrlen);
498
          DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
499
                      m->m_len, errno,strerror(errno)));
500
          if(m->m_len<0) {
501
            u_char code=ICMP_UNREACH_PORT;
502

    
503
            if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
504
            else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
505

    
506
            DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
507
            icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
508
            m_free(m);
509
          } else {
510
          /*
511
           * Hack: domain name lookup will be used the most for UDP,
512
           * and since they'll only be used once there's no need
513
           * for the 4 minute (or whatever) timeout... So we time them
514
           * out much quicker (10 seconds  for now...)
515
           */
516
            if (so->so_expire) {
517
              if (so->so_fport == htons(53))
518
                so->so_expire = curtime + SO_EXPIREFAST;
519
              else
520
                so->so_expire = curtime + SO_EXPIRE;
521
            }
522

    
523
            /*
524
             * If this packet was destined for CTL_ADDR,
525
             * make it look like that's where it came from, done by udp_output
526
             */
527
            udp_output(so, m, &addr);
528
          } /* rx error */
529
        } /* if ping packet */
530
}
531

    
532
/*
533
 * sendto() a socket
534
 */
535
int
536
sosendto(struct socket *so, struct mbuf *m)
537
{
538
        Slirp *slirp = so->slirp;
539
        int ret;
540
        struct sockaddr_in addr;
541

    
542
        DEBUG_CALL("sosendto");
543
        DEBUG_ARG("so = %lx", (long)so);
544
        DEBUG_ARG("m = %lx", (long)m);
545

    
546
        addr.sin_family = AF_INET;
547
        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
548
            slirp->vnetwork_addr.s_addr) {
549
          /* It's an alias */
550
          if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
551
            if (get_dns_addr(&addr.sin_addr) < 0)
552
              addr.sin_addr = loopback_addr;
553
          } else {
554
            addr.sin_addr = loopback_addr;
555
          }
556
        } else
557
          addr.sin_addr = so->so_faddr;
558
        addr.sin_port = so->so_fport;
559

    
560
        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)));
561

    
562
        /* Don't care what port we get */
563
        ret = sendto(so->s, m->m_data, m->m_len, 0,
564
                     (struct sockaddr *)&addr, sizeof (struct sockaddr));
565
        if (ret < 0)
566
                return -1;
567

    
568
        /*
569
         * Kill the socket if there's no reply in 4 minutes,
570
         * but only if it's an expirable socket
571
         */
572
        if (so->so_expire)
573
                so->so_expire = curtime + SO_EXPIRE;
574
        so->so_state &= SS_PERSISTENT_MASK;
575
        so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */
576
        return 0;
577
}
578

    
579
/*
580
 * Listen for incoming TCP connections
581
 */
582
struct socket *
583
tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
584
           u_int lport, int flags)
585
{
586
        struct sockaddr_in addr;
587
        struct socket *so;
588
        int s, opt = 1;
589
        socklen_t addrlen = sizeof(addr);
590
        memset(&addr, 0, addrlen);
591

    
592
        DEBUG_CALL("tcp_listen");
593
        DEBUG_ARG("haddr = %x", haddr);
594
        DEBUG_ARG("hport = %d", hport);
595
        DEBUG_ARG("laddr = %x", laddr);
596
        DEBUG_ARG("lport = %d", lport);
597
        DEBUG_ARG("flags = %x", flags);
598

    
599
        so = socreate(slirp);
600
        if (!so) {
601
          return NULL;
602
        }
603

    
604
        /* Don't tcp_attach... we don't need so_snd nor so_rcv */
605
        if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
606
                free(so);
607
                return NULL;
608
        }
609
        insque(so, &slirp->tcb);
610

    
611
        /*
612
         * SS_FACCEPTONCE sockets must time out.
613
         */
614
        if (flags & SS_FACCEPTONCE)
615
           so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
616

    
617
        so->so_state &= SS_PERSISTENT_MASK;
618
        so->so_state |= (SS_FACCEPTCONN | flags);
619
        so->so_lport = lport; /* Kept in network format */
620
        so->so_laddr.s_addr = laddr; /* Ditto */
621

    
622
        addr.sin_family = AF_INET;
623
        addr.sin_addr.s_addr = haddr;
624
        addr.sin_port = hport;
625

    
626
        if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
627
            (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
628
            (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
629
            (listen(s,1) < 0)) {
630
                int tmperrno = errno; /* Don't clobber the real reason we failed */
631

    
632
                close(s);
633
                sofree(so);
634
                /* Restore the real errno */
635
#ifdef _WIN32
636
                WSASetLastError(tmperrno);
637
#else
638
                errno = tmperrno;
639
#endif
640
                return NULL;
641
        }
642
        setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
643

    
644
        getsockname(s,(struct sockaddr *)&addr,&addrlen);
645
        so->so_fport = addr.sin_port;
646
        if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
647
           so->so_faddr = slirp->vhost_addr;
648
        else
649
           so->so_faddr = addr.sin_addr;
650

    
651
        so->s = s;
652
        return so;
653
}
654

    
655
/*
656
 * Various session state calls
657
 * XXX Should be #define's
658
 * The socket state stuff needs work, these often get call 2 or 3
659
 * times each when only 1 was needed
660
 */
661
void
662
soisfconnecting(struct socket *so)
663
{
664
        so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
665
                          SS_FCANTSENDMORE|SS_FWDRAIN);
666
        so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
667
}
668

    
669
void
670
soisfconnected(struct socket *so)
671
{
672
        so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
673
        so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
674
}
675

    
676
static void
677
sofcantrcvmore(struct socket *so)
678
{
679
        if ((so->so_state & SS_NOFDREF) == 0) {
680
                shutdown(so->s,0);
681
                if(global_writefds) {
682
                  FD_CLR(so->s,global_writefds);
683
                }
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

    
694
static void
695
sofcantsendmore(struct socket *so)
696
{
697
        if ((so->so_state & SS_NOFDREF) == 0) {
698
            shutdown(so->s,1);           /* send FIN to fhost */
699
            if (global_readfds) {
700
                FD_CLR(so->s,global_readfds);
701
            }
702
            if (global_xfds) {
703
                FD_CLR(so->s,global_xfds);
704
            }
705
        }
706
        so->so_state &= ~(SS_ISFCONNECTING);
707
        if (so->so_state & SS_FCANTRCVMORE) {
708
           so->so_state &= SS_PERSISTENT_MASK;
709
           so->so_state |= SS_NOFDREF; /* as above */
710
        } else {
711
           so->so_state |= SS_FCANTSENDMORE;
712
        }
713
}
714

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