Statistics
| Branch: | Revision:

root / slirp / udp.c @ 0d62c4cf

History | View | Annotate | Download (16.6 kB)

1
/*
2
 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3
 *        The Regents of the University of California.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the University nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 *        @(#)udp_usrreq.c        8.4 (Berkeley) 1/21/94
30
 * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
31
 */
32

    
33
/*
34
 * Changes and additions relating to SLiRP
35
 * Copyright (c) 1995 Danny Gasparovski.
36
 *
37
 * Please read the file COPYRIGHT for the
38
 * terms and conditions of the copyright.
39
 */
40

    
41
#include <slirp.h>
42
#include "ip_icmp.h"
43

    
44
#ifdef LOG_ENABLED
45
struct udpstat udpstat;
46
#endif
47

    
48
struct socket udb;
49

    
50
static u_int8_t udp_tos(struct socket *so);
51
static void udp_emu(struct socket *so, struct mbuf *m);
52

    
53
struct        socket *udp_last_so = &udb;
54

    
55
void
56
udp_init(void)
57
{
58
        udb.so_next = udb.so_prev = &udb;
59
}
60
/* m->m_data  points at ip packet header
61
 * m->m_len   length ip packet
62
 * ip->ip_len length data (IPDU)
63
 */
64
void
65
udp_input(register struct mbuf *m, int iphlen)
66
{
67
        register struct ip *ip;
68
        register struct udphdr *uh;
69
        int len;
70
        struct ip save_ip;
71
        struct socket *so;
72

    
73
        DEBUG_CALL("udp_input");
74
        DEBUG_ARG("m = %lx", (long)m);
75
        DEBUG_ARG("iphlen = %d", iphlen);
76

    
77
        STAT(udpstat.udps_ipackets++);
78

    
79
        /*
80
         * Strip IP options, if any; should skip this,
81
         * make available to user, and use on returned packets,
82
         * but we don't yet have a way to check the checksum
83
         * with options still present.
84
         */
85
        if(iphlen > sizeof(struct ip)) {
86
                ip_stripoptions(m, (struct mbuf *)0);
87
                iphlen = sizeof(struct ip);
88
        }
89

    
90
        /*
91
         * Get IP and UDP header together in first mbuf.
92
         */
93
        ip = mtod(m, struct ip *);
94
        uh = (struct udphdr *)((caddr_t)ip + iphlen);
95

    
96
        /*
97
         * Make mbuf data length reflect UDP length.
98
         * If not enough data to reflect UDP length, drop.
99
         */
100
        len = ntohs((u_int16_t)uh->uh_ulen);
101

    
102
        if (ip->ip_len != len) {
103
                if (len > ip->ip_len) {
104
                        STAT(udpstat.udps_badlen++);
105
                        goto bad;
106
                }
107
                m_adj(m, len - ip->ip_len);
108
                ip->ip_len = len;
109
        }
110

    
111
        /*
112
         * Save a copy of the IP header in case we want restore it
113
         * for sending an ICMP error message in response.
114
         */
115
        save_ip = *ip;
116
        save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
117

    
118
        /*
119
         * Checksum extended UDP header and data.
120
         */
121
        if (uh->uh_sum) {
122
      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
123
          ((struct ipovly *)ip)->ih_x1 = 0;
124
          ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
125
          if(cksum(m, len + sizeof(struct ip))) {
126
            STAT(udpstat.udps_badsum++);
127
            goto bad;
128
          }
129
        }
130

    
131
        /*
132
         *  handle DHCP/BOOTP
133
         */
134
        if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
135
            bootp_input(m);
136
            goto bad;
137
        }
138

    
139
        if (slirp_restrict)
140
            goto bad;
141

    
142
        /*
143
         *  handle TFTP
144
         */
145
        if (ntohs(uh->uh_dport) == TFTP_SERVER) {
146
            tftp_input(m);
147
            goto bad;
148
        }
149

    
150
        /*
151
         * Locate pcb for datagram.
152
         */
153
        so = udp_last_so;
154
        if (so->so_lport != uh->uh_sport ||
155
            so->so_laddr.s_addr != ip->ip_src.s_addr) {
156
                struct socket *tmp;
157

    
158
                for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
159
                        if (tmp->so_lport == uh->uh_sport &&
160
                            tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
161
                                so = tmp;
162
                                break;
163
                        }
164
                }
165
                if (tmp == &udb) {
166
                  so = NULL;
167
                } else {
168
                  STAT(udpstat.udpps_pcbcachemiss++);
169
                  udp_last_so = so;
170
                }
171
        }
172

    
173
        if (so == NULL) {
174
          /*
175
           * If there's no socket for this packet,
176
           * create one
177
           */
178
          if ((so = socreate()) == NULL) goto bad;
179
          if(udp_attach(so) == -1) {
180
            DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
181
                        errno,strerror(errno)));
182
            sofree(so);
183
            goto bad;
184
          }
185

    
186
          /*
187
           * Setup fields
188
           */
189
          so->so_laddr = ip->ip_src;
190
          so->so_lport = uh->uh_sport;
191

    
192
          if ((so->so_iptos = udp_tos(so)) == 0)
193
            so->so_iptos = ip->ip_tos;
194

    
195
          /*
196
           * XXXXX Here, check if it's in udpexec_list,
197
           * and if it is, do the fork_exec() etc.
198
           */
199
        }
200

    
201
        so->so_faddr = ip->ip_dst; /* XXX */
202
        so->so_fport = uh->uh_dport; /* XXX */
203

    
204
        iphlen += sizeof(struct udphdr);
205
        m->m_len -= iphlen;
206
        m->m_data += iphlen;
207

    
208
        /*
209
         * Now we sendto() the packet.
210
         */
211
        if (so->so_emu)
212
           udp_emu(so, m);
213

    
214
        if(sosendto(so,m) == -1) {
215
          m->m_len += iphlen;
216
          m->m_data -= iphlen;
217
          *ip=save_ip;
218
          DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
219
          icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
220
        }
221

    
222
        m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
223

    
224
        /* restore the orig mbuf packet */
225
        m->m_len += iphlen;
226
        m->m_data -= iphlen;
227
        *ip=save_ip;
228
        so->so_m=m;         /* ICMP backup */
229

    
230
        return;
231
bad:
232
        m_freem(m);
233
        return;
234
}
235

    
236
int udp_output2(struct socket *so, struct mbuf *m,
237
                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
238
                int iptos)
239
{
240
        register struct udpiphdr *ui;
241
        int error = 0;
242

    
243
        DEBUG_CALL("udp_output");
244
        DEBUG_ARG("so = %lx", (long)so);
245
        DEBUG_ARG("m = %lx", (long)m);
246
        DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
247
        DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
248

    
249
        /*
250
         * Adjust for header
251
         */
252
        m->m_data -= sizeof(struct udpiphdr);
253
        m->m_len += sizeof(struct udpiphdr);
254

    
255
        /*
256
         * Fill in mbuf with extended UDP header
257
         * and addresses and length put into network format.
258
         */
259
        ui = mtod(m, struct udpiphdr *);
260
    memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
261
        ui->ui_x1 = 0;
262
        ui->ui_pr = IPPROTO_UDP;
263
        ui->ui_len = htons(m->m_len - sizeof(struct ip));
264
        /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
265
        ui->ui_src = saddr->sin_addr;
266
        ui->ui_dst = daddr->sin_addr;
267
        ui->ui_sport = saddr->sin_port;
268
        ui->ui_dport = daddr->sin_port;
269
        ui->ui_ulen = ui->ui_len;
270

    
271
        /*
272
         * Stuff checksum and output datagram.
273
         */
274
        ui->ui_sum = 0;
275
        if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
276
                ui->ui_sum = 0xffff;
277
        ((struct ip *)ui)->ip_len = m->m_len;
278

    
279
        ((struct ip *)ui)->ip_ttl = IPDEFTTL;
280
        ((struct ip *)ui)->ip_tos = iptos;
281

    
282
        STAT(udpstat.udps_opackets++);
283

    
284
        error = ip_output(so, m);
285

    
286
        return (error);
287
}
288

    
289
int udp_output(struct socket *so, struct mbuf *m,
290
               struct sockaddr_in *addr)
291

    
292
{
293
    struct sockaddr_in saddr, daddr;
294

    
295
    saddr = *addr;
296
    if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) {
297
        if ((so->so_faddr.s_addr & ~vnetwork_mask.s_addr) ==
298
            ~vnetwork_mask.s_addr) {
299
            saddr.sin_addr = vhost_addr;
300
        } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
301
                   so->so_faddr.s_addr != vhost_addr.s_addr) {
302
            saddr.sin_addr = so->so_faddr;
303
        }
304
    }
305
    daddr.sin_addr = so->so_laddr;
306
    daddr.sin_port = so->so_lport;
307

    
308
    return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
309
}
310

    
311
int
312
udp_attach(struct socket *so)
313
{
314
  struct sockaddr_in addr;
315

    
316
  if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
317
    /*
318
     * Here, we bind() the socket.  Although not really needed
319
     * (sendto() on an unbound socket will bind it), it's done
320
     * here so that emulation of ytalk etc. don't have to do it
321
     */
322
    addr.sin_family = AF_INET;
323
    addr.sin_port = 0;
324
    addr.sin_addr.s_addr = INADDR_ANY;
325
    if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
326
      int lasterrno=errno;
327
      closesocket(so->s);
328
      so->s=-1;
329
#ifdef _WIN32
330
      WSASetLastError(lasterrno);
331
#else
332
      errno=lasterrno;
333
#endif
334
    } else {
335
      /* success, insert in queue */
336
      so->so_expire = curtime + SO_EXPIRE;
337
      insque(so,&udb);
338
    }
339
  }
340
  return(so->s);
341
}
342

    
343
void
344
udp_detach(struct socket *so)
345
{
346
        closesocket(so->s);
347
        sofree(so);
348
}
349

    
350
static const struct tos_t udptos[] = {
351
        {0, 53, IPTOS_LOWDELAY, 0},                        /* DNS */
352
        {517, 517, IPTOS_LOWDELAY, EMU_TALK},        /* talk */
353
        {518, 518, IPTOS_LOWDELAY, EMU_NTALK},        /* ntalk */
354
        {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME},        /* Cu-Seeme */
355
        {0, 0, 0, 0}
356
};
357

    
358
static u_int8_t
359
udp_tos(struct socket *so)
360
{
361
        int i = 0;
362

    
363
        while(udptos[i].tos) {
364
                if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
365
                    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
366
                            so->so_emu = udptos[i].emu;
367
                        return udptos[i].tos;
368
                }
369
                i++;
370
        }
371

    
372
        return 0;
373
}
374

    
375
#ifdef EMULATE_TALK
376
#include "talkd.h"
377
#endif
378

    
379
/*
380
 * Here, talk/ytalk/ntalk requests must be emulated
381
 */
382
static void
383
udp_emu(struct socket *so, struct mbuf *m)
384
{
385
        struct sockaddr_in addr;
386
        socklen_t addrlen = sizeof(addr);
387
#ifdef EMULATE_TALK
388
        CTL_MSG_OLD *omsg;
389
        CTL_MSG *nmsg;
390
        char buff[sizeof(CTL_MSG)];
391
        u_char type;
392

    
393
struct talk_request {
394
        struct talk_request *next;
395
        struct socket *udp_so;
396
        struct socket *tcp_so;
397
} *req;
398

    
399
        static struct talk_request *req_tbl = 0;
400

    
401
#endif
402

    
403
struct cu_header {
404
        uint16_t        d_family;                // destination family
405
        uint16_t        d_port;                        // destination port
406
        uint32_t        d_addr;                        // destination address
407
        uint16_t        s_family;                // source family
408
        uint16_t        s_port;                        // source port
409
        uint32_t        so_addr;                // source address
410
        uint32_t        seqn;                        // sequence number
411
        uint16_t        message;                // message
412
        uint16_t        data_type;                // data type
413
        uint16_t        pkt_len;                // packet length
414
} *cu_head;
415

    
416
        switch(so->so_emu) {
417

    
418
#ifdef EMULATE_TALK
419
         case EMU_TALK:
420
         case EMU_NTALK:
421
                /*
422
                 * Talk emulation. We always change the ctl_addr to get
423
                 * some answers from the daemon. When an ANNOUNCE comes,
424
                 * we send LEAVE_INVITE to the local daemons. Also when a
425
                 * DELETE comes, we send copies to the local daemons.
426
                 */
427
                if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
428
                        return;
429

    
430
#define        IS_OLD        (so->so_emu == EMU_TALK)
431

    
432
#define COPY_MSG(dest, src) { dest->type = src->type; \
433
                              dest->id_num = src->id_num; \
434
                              dest->pid = src->pid; \
435
                              dest->addr = src->addr; \
436
                              dest->ctl_addr = src->ctl_addr; \
437
                              memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
438
                              memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
439
                               memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
440

    
441
#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
442
/* old_sockaddr to sockaddr_in */
443

    
444

    
445
                if (IS_OLD) {                  /* old talk */
446
                        omsg = mtod(m, CTL_MSG_OLD*);
447
                        nmsg = (CTL_MSG *) buff;
448
                        type = omsg->type;
449
                        OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
450
                        OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
451
                        pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin());
452
                } else {                /* new talk */
453
                        omsg = (CTL_MSG_OLD *) buff;
454
                        nmsg = mtod(m, CTL_MSG *);
455
                        type = nmsg->type;
456
                        OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
457
                        OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
458
                        pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin());
459
                }
460

    
461
                if (type == LOOK_UP)
462
                        return;                /* for LOOK_UP this is enough */
463

    
464
                if (IS_OLD) {                /* make a copy of the message */
465
                        COPY_MSG(nmsg, omsg);
466
                        nmsg->vers = 1;
467
                        nmsg->answer = 0;
468
                } else
469
                        COPY_MSG(omsg, nmsg);
470

    
471
                /*
472
                 * If if is an ANNOUNCE message, we go through the
473
                 * request table to see if a tcp port has already
474
                 * been redirected for this socket. If not, we solisten()
475
                 * a new socket and add this entry to the table.
476
                 * The port number of the tcp socket and our IP
477
                 * are put to the addr field of the message structures.
478
                 * Then a LEAVE_INVITE is sent to both local daemon
479
                 * ports, 517 and 518. This is why we have two copies
480
                 * of the message, one in old talk and one in new talk
481
                 * format.
482
                 */
483

    
484
                if (type == ANNOUNCE) {
485
                        int s;
486
                        u_short temp_port;
487

    
488
                        for(req = req_tbl; req; req = req->next)
489
                                if (so == req->udp_so)
490
                                        break;          /* found it */
491

    
492
                        if (!req) {        /* no entry for so, create new */
493
                                req = (struct talk_request *)
494
                                        malloc(sizeof(struct talk_request));
495
                                req->udp_so = so;
496
                                req->tcp_so = solisten(0,
497
                                        OTOSIN(omsg, addr)->sin_addr.s_addr,
498
                                        OTOSIN(omsg, addr)->sin_port,
499
                                        SS_FACCEPTONCE);
500
                                req->next = req_tbl;
501
                                req_tbl = req;
502
                        }
503

    
504
                        /* replace port number in addr field */
505
                        addrlen = sizeof(addr);
506
                        getsockname(req->tcp_so->s,
507
                                        (struct sockaddr *) &addr,
508
                                        &addrlen);
509
                        OTOSIN(omsg, addr)->sin_port = addr.sin_port;
510
                        OTOSIN(omsg, addr)->sin_addr = our_addr;
511
                        OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
512
                        OTOSIN(nmsg, addr)->sin_addr = our_addr;
513

    
514
                        /* send LEAVE_INVITEs */
515
                        temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
516
                        OTOSIN(omsg, ctl_addr)->sin_port = 0;
517
                        OTOSIN(nmsg, ctl_addr)->sin_port = 0;
518
                        omsg->type = nmsg->type = LEAVE_INVITE;
519

    
520
                        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
521
                        addr.sin_addr = our_addr;
522
                        addr.sin_family = AF_INET;
523
                        addr.sin_port = htons(517);
524
                        sendto(s, (char *)omsg, sizeof(*omsg), 0,
525
                                (struct sockaddr *)&addr, sizeof(addr));
526
                        addr.sin_port = htons(518);
527
                        sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
528
                                (struct sockaddr *) &addr, sizeof(addr));
529
                        closesocket(s) ;
530

    
531
                        omsg->type = nmsg->type = ANNOUNCE;
532
                        OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
533
                        OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
534
                }
535

    
536
                /*
537
                 * If it is a DELETE message, we send a copy to the
538
                 * local daemons. Then we delete the entry corresponding
539
                 * to our socket from the request table.
540
                 */
541

    
542
                if (type == DELETE) {
543
                        struct talk_request *temp_req, *req_next;
544
                        int s;
545
                        u_short temp_port;
546

    
547
                        temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
548
                        OTOSIN(omsg, ctl_addr)->sin_port = 0;
549
                        OTOSIN(nmsg, ctl_addr)->sin_port = 0;
550

    
551
                        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
552
                        addr.sin_addr = our_addr;
553
                        addr.sin_family = AF_INET;
554
                        addr.sin_port = htons(517);
555
                        sendto(s, (char *)omsg, sizeof(*omsg), 0,
556
                                (struct sockaddr *)&addr, sizeof(addr));
557
                        addr.sin_port = htons(518);
558
                        sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
559
                                (struct sockaddr *)&addr, sizeof(addr));
560
                        closesocket(s);
561

    
562
                        OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
563
                        OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
564

    
565
                        /* delete table entry */
566
                        if (so == req_tbl->udp_so) {
567
                                temp_req = req_tbl;
568
                                req_tbl = req_tbl->next;
569
                                free(temp_req);
570
                        } else {
571
                                temp_req = req_tbl;
572
                                for(req = req_tbl->next; req; req = req_next) {
573
                                        req_next = req->next;
574
                                        if (so == req->udp_so) {
575
                                                temp_req->next = req_next;
576
                                                free(req);
577
                                                break;
578
                                        } else {
579
                                                temp_req = req;
580
                                        }
581
                                }
582
                        }
583
                }
584

    
585
                return;
586
#endif
587

    
588
        case EMU_CUSEEME:
589

    
590
                /*
591
                 * Cu-SeeMe emulation.
592
                 * Hopefully the packet is more that 16 bytes long. We don't
593
                 * do any other tests, just replace the address and port
594
                 * fields.
595
                 */
596
                if (m->m_len >= sizeof (*cu_head)) {
597
                        if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
598
                                return;
599
                        cu_head = mtod(m, struct cu_header *);
600
                        cu_head->s_port = addr.sin_port;
601
                        cu_head->so_addr = our_addr.s_addr;
602
                }
603

    
604
                return;
605
        }
606
}
607

    
608
struct socket *
609
udp_listen(u_int32_t haddr, u_int hport, u_int32_t laddr, u_int lport,
610
           int flags)
611
{
612
        struct sockaddr_in addr;
613
        struct socket *so;
614
        socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
615

    
616
        if ((so = socreate()) == NULL) {
617
                free(so);
618
                return NULL;
619
        }
620
        so->s = socket(AF_INET,SOCK_DGRAM,0);
621
        so->so_expire = curtime + SO_EXPIRE;
622
        insque(so,&udb);
623

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

    
628
        if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
629
                udp_detach(so);
630
                return NULL;
631
        }
632
        setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
633

    
634
        getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
635
        so->so_fport = addr.sin_port;
636
        if (addr.sin_addr.s_addr == 0 ||
637
            addr.sin_addr.s_addr == loopback_addr.s_addr) {
638
           so->so_faddr = vhost_addr;
639
        } else {
640
           so->so_faddr = addr.sin_addr;
641
        }
642
        so->so_lport = lport;
643
        so->so_laddr.s_addr = laddr;
644
        if (flags != SS_FACCEPTONCE)
645
           so->so_expire = 0;
646

    
647
        so->so_state &= SS_PERSISTENT_MASK;
648
        so->so_state |= SS_ISFCONNECTED | flags;
649

    
650
        return so;
651
}