Statistics
| Branch: | Revision:

root / slirp / socket.c @ 460fec67

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
        len = sb->sb_datalen - sb->sb_cc;
94

    
95
        if (len <= 0)
96
                return 0;
97

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

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

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

    
156
        DEBUG_CALL("soread");
157
        DEBUG_ARG("so = %lx", (long )so);
158

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

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

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

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

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

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

    
216
        DEBUG_CALL("soreadbuf");
217
        DEBUG_ARG("so = %lx", (long )so);
218

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

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

    
229
    copy -= nn;
230
    buf += nn;
231

    
232
    if (copy == 0)
233
        goto done;
234

    
235
    memcpy(iov[1].iov_base, buf, copy);
236

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

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

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

    
264
        DEBUG_CALL("sorecvoob");
265
        DEBUG_ARG("so = %lx", (long)so);
266

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

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

    
292
        int n, len;
293

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

    
298
        if (so->so_urgc > 2048)
299
           so->so_urgc = 2048; /* XXXX */
300

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

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

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

    
337
        return n;
338
}
339

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

    
352
        DEBUG_CALL("sowrite");
353
        DEBUG_ARG("so = %lx", (long)so);
354

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

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

    
366
        len = sb->sb_cc;
367

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

    
390
#ifdef HAVE_READV
391
        nn = writev(so->s, (const struct iovec *)iov, n);
392

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

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

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

    
419
        /* Update sbuf */
420
        sb->sb_cc -= nn;
421
        sb->sb_rptr += nn;
422
        if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
423
                sb->sb_rptr -= sb->sb_datalen;
424

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

    
432
        return nn;
433
}
434

    
435
/*
436
 * recvfrom() a UDP socket
437
 */
438
void
439
sorecvfrom(struct socket *so)
440
{
441
        struct sockaddr_in addr;
442
        socklen_t addrlen = sizeof(struct sockaddr_in);
443

    
444
        DEBUG_CALL("sorecvfrom");
445
        DEBUG_ARG("so = %lx", (long)so);
446

    
447
        if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
448
          char buff[256];
449
          int len;
450

    
451
          len = recvfrom(so->s, buff, 256, 0,
452
                         (struct sockaddr *)&addr, &addrlen);
453
          /* XXX Check if reply is "correct"? */
454

    
455
          if(len == -1 || len == 0) {
456
            u_char code=ICMP_UNREACH_PORT;
457

    
458
            if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
459
            else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
460

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

    
479
          m = m_get(so->slirp);
480
          if (!m) {
481
              return;
482
          }
483
          m->m_data += IF_MAXLINKHDR;
484

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

    
493
          if (n > len) {
494
            n = (m->m_data - m->m_dat) + m->m_len + n + 1;
495
            m_inc(m, n);
496
            len = M_FREEROOM(m);
497
          }
498
          /* } */
499

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

    
507
            if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
508
            else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
509

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

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

    
536
/*
537
 * sendto() a socket
538
 */
539
int
540
sosendto(struct socket *so, struct mbuf *m)
541
{
542
        Slirp *slirp = so->slirp;
543
        int ret;
544
        struct sockaddr_in addr;
545

    
546
        DEBUG_CALL("sosendto");
547
        DEBUG_ARG("so = %lx", (long)so);
548
        DEBUG_ARG("m = %lx", (long)m);
549

    
550
        addr.sin_family = AF_INET;
551
        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
552
            slirp->vnetwork_addr.s_addr) {
553
          /* It's an alias */
554
          if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
555
            addr.sin_addr = dns_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
 */
585
struct socket *
586
tcp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_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

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

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

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

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

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

    
624
        addr.sin_family = AF_INET;
625
        addr.sin_addr.s_addr = haddr;
626
        addr.sin_port = hport;
627

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

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

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

    
653
        so->s = s;
654
        return so;
655
}
656

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

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

    
678
static void
679
sofcantrcvmore(struct socket *so)
680
{
681
        if ((so->so_state & SS_NOFDREF) == 0) {
682
                shutdown(so->s,0);
683
                if(global_writefds) {
684
                  FD_CLR(so->s,global_writefds);
685
                }
686
        }
687
        so->so_state &= ~(SS_ISFCONNECTING);
688
        if (so->so_state & SS_FCANTSENDMORE) {
689
           so->so_state &= SS_PERSISTENT_MASK;
690
           so->so_state |= SS_NOFDREF; /* Don't select it */
691
        } else {
692
           so->so_state |= SS_FCANTRCVMORE;
693
        }
694
}
695

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

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