~ubuntu-branches/ubuntu/feisty/basilisk2/feisty

« back to all changes in this revision

Viewing changes to src/slirp/socket.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2005-07-30 20:42:20 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050730204220-1nl1cg2jkjvy63ry
Tags: 0.9.20050730-1
* New upstream CVS snapshot.
* Build-depend on virtual libsdl-dev (not libsdl1.2-dev).
* Invoke init rules also on clean (to separate better from official
  builds).
* Update URL of upstream source in debian/copyright.

Show diffs side-by-side

added added

removed removed

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