ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/udp.c
Revision: 1.7
Committed: 2010-08-22T19:43:29Z (14 years, 1 month ago) by asvitkine
Content type: text/plain
Branch: MAIN
Changes since 1.6: +1 -0 lines
Log Message:
Fix warning with undeclared free() with clang

File Contents

# User Rev Content
1 gbeauche 1.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. All advertising materials mentioning features or use of this software
14     * must display the following acknowledgement:
15     * This product includes software developed by the University of
16     * California, Berkeley and its contributors.
17     * 4. Neither the name of the University nor the names of its contributors
18     * may be used to endorse or promote products derived from this software
19     * without specific prior written permission.
20     *
21     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24     * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31     * SUCH DAMAGE.
32     *
33     * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
34     * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
35     */
36    
37     /*
38     * Changes and additions relating to SLiRP
39     * Copyright (c) 1995 Danny Gasparovski.
40     *
41     * Please read the file COPYRIGHT for the
42     * terms and conditions of the copyright.
43     */
44    
45 asvitkine 1.7 #include <stdlib.h>
46 gbeauche 1.1 #include <slirp.h>
47     #include "ip_icmp.h"
48    
49     struct udpstat udpstat;
50    
51     struct socket udb;
52    
53     /*
54     * UDP protocol implementation.
55     * Per RFC 768, August, 1980.
56     */
57     #ifndef COMPAT_42
58     int udpcksum = 1;
59     #else
60     int udpcksum = 0; /* XXX */
61     #endif
62    
63     struct socket *udp_last_so = &udb;
64    
65     void
66     udp_init()
67     {
68     udb.so_next = udb.so_prev = &udb;
69     }
70     /* m->m_data points at ip packet header
71     * m->m_len length ip packet
72     * ip->ip_len length data (IPDU)
73     */
74     void
75     udp_input(m, iphlen)
76     register struct mbuf *m;
77     int iphlen;
78     {
79     register struct ip *ip;
80     register struct udphdr *uh;
81     /* struct mbuf *opts = 0;*/
82     int len;
83     struct ip save_ip;
84     struct socket *so;
85    
86     DEBUG_CALL("udp_input");
87     DEBUG_ARG("m = %lx", (long)m);
88     DEBUG_ARG("iphlen = %d", iphlen);
89    
90     udpstat.udps_ipackets++;
91    
92     /*
93     * Strip IP options, if any; should skip this,
94     * make available to user, and use on returned packets,
95     * but we don't yet have a way to check the checksum
96     * with options still present.
97     */
98     if(iphlen > sizeof(struct ip)) {
99     ip_stripoptions(m, (struct mbuf *)0);
100     iphlen = sizeof(struct ip);
101     }
102    
103     /*
104     * Get IP and UDP header together in first mbuf.
105     */
106     ip = mtod(m, struct ip *);
107     uh = (struct udphdr *)((caddr_t)ip + iphlen);
108    
109     /*
110     * Make mbuf data length reflect UDP length.
111     * If not enough data to reflect UDP length, drop.
112     */
113     len = ntohs((u_int16_t)uh->uh_ulen);
114    
115     if (ip->ip_len != len) {
116     if (len > ip->ip_len) {
117     udpstat.udps_badlen++;
118     goto bad;
119     }
120     m_adj(m, len - ip->ip_len);
121     ip->ip_len = len;
122     }
123    
124     /*
125     * Save a copy of the IP header in case we want restore it
126     * for sending an ICMP error message in response.
127     */
128     save_ip = *ip;
129     save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
130    
131     /*
132     * Checksum extended UDP header and data.
133     */
134     if (udpcksum && uh->uh_sum) {
135     ((struct ipovly *)ip)->ih_next = 0;
136     ((struct ipovly *)ip)->ih_prev = 0;
137     ((struct ipovly *)ip)->ih_x1 = 0;
138     ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
139     /* keep uh_sum for ICMP reply
140     * uh->uh_sum = cksum(m, len + sizeof (struct ip));
141     * if (uh->uh_sum) {
142     */
143     if(cksum(m, len + sizeof(struct ip))) {
144     udpstat.udps_badsum++;
145     goto bad;
146     }
147     }
148    
149     /*
150     * handle DHCP/BOOTP
151     */
152     if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
153     bootp_input(m);
154     goto bad;
155     }
156    
157     /*
158     * handle TFTP
159     */
160     if (ntohs(uh->uh_dport) == TFTP_SERVER) {
161     tftp_input(m);
162     goto bad;
163     }
164    
165     /*
166     * Locate pcb for datagram.
167     */
168     so = udp_last_so;
169     if (so->so_lport != uh->uh_sport ||
170     so->so_laddr.s_addr != ip->ip_src.s_addr) {
171     struct socket *tmp;
172    
173     for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
174     if (tmp->so_lport == uh->uh_sport &&
175     tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
176     tmp->so_faddr.s_addr = ip->ip_dst.s_addr;
177     tmp->so_fport = uh->uh_dport;
178     so = tmp;
179     break;
180     }
181     }
182     if (tmp == &udb) {
183     so = NULL;
184     } else {
185     udpstat.udpps_pcbcachemiss++;
186     udp_last_so = so;
187     }
188     }
189    
190     if (so == NULL) {
191     /*
192     * If there's no socket for this packet,
193     * create one
194     */
195     if ((so = socreate()) == NULL) goto bad;
196     if(udp_attach(so) == -1) {
197     DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
198     errno,strerror(errno)));
199     sofree(so);
200     goto bad;
201     }
202    
203     /*
204     * Setup fields
205     */
206     /* udp_last_so = so; */
207     so->so_laddr = ip->ip_src;
208     so->so_lport = uh->uh_sport;
209    
210     if ((so->so_iptos = udp_tos(so)) == 0)
211     so->so_iptos = ip->ip_tos;
212    
213     /*
214     * XXXXX Here, check if it's in udpexec_list,
215     * and if it is, do the fork_exec() etc.
216     */
217     }
218    
219 gbeauche 1.6 so->so_faddr = ip->ip_dst; /* XXX */
220     so->so_fport = uh->uh_dport; /* XXX */
221    
222 gbeauche 1.1 iphlen += sizeof(struct udphdr);
223     m->m_len -= iphlen;
224     m->m_data += iphlen;
225    
226     /*
227     * Now we sendto() the packet.
228     */
229     if (so->so_emu)
230     udp_emu(so, m);
231    
232     if(sosendto(so,m) == -1) {
233     m->m_len += iphlen;
234     m->m_data -= iphlen;
235     *ip=save_ip;
236     DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
237     icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
238     }
239    
240     m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
241    
242     /* restore the orig mbuf packet */
243     m->m_len += iphlen;
244     m->m_data -= iphlen;
245     *ip=save_ip;
246     so->so_m=m; /* ICMP backup */
247    
248     return;
249     bad:
250     m_freem(m);
251     /* if (opts) m_freem(opts); */
252     return;
253     }
254    
255     int udp_output2(struct socket *so, struct mbuf *m,
256     struct sockaddr_in *saddr, struct sockaddr_in *daddr,
257     int iptos)
258     {
259     register struct udpiphdr *ui;
260     int error = 0;
261    
262     DEBUG_CALL("udp_output");
263     DEBUG_ARG("so = %lx", (long)so);
264     DEBUG_ARG("m = %lx", (long)m);
265     DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
266     DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
267    
268     /*
269     * Adjust for header
270     */
271     m->m_data -= sizeof(struct udpiphdr);
272     m->m_len += sizeof(struct udpiphdr);
273    
274     /*
275     * Fill in mbuf with extended UDP header
276     * and addresses and length put into network format.
277     */
278     ui = mtod(m, struct udpiphdr *);
279     ui->ui_next = ui->ui_prev = 0;
280     ui->ui_x1 = 0;
281     ui->ui_pr = IPPROTO_UDP;
282     ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
283     /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
284     ui->ui_src = saddr->sin_addr;
285     ui->ui_dst = daddr->sin_addr;
286     ui->ui_sport = saddr->sin_port;
287     ui->ui_dport = daddr->sin_port;
288     ui->ui_ulen = ui->ui_len;
289    
290     /*
291     * Stuff checksum and output datagram.
292     */
293     ui->ui_sum = 0;
294     if (udpcksum) {
295     if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
296     ui->ui_sum = 0xffff;
297     }
298     ((struct ip *)ui)->ip_len = m->m_len;
299    
300     ((struct ip *)ui)->ip_ttl = ip_defttl;
301     ((struct ip *)ui)->ip_tos = iptos;
302    
303     udpstat.udps_opackets++;
304    
305     error = ip_output(so, m);
306    
307     return (error);
308     }
309    
310     int udp_output(struct socket *so, struct mbuf *m,
311     struct sockaddr_in *addr)
312    
313     {
314     struct sockaddr_in saddr, daddr;
315    
316     saddr = *addr;
317 gbeauche 1.5 if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
318 gbeauche 1.1 saddr.sin_addr.s_addr = so->so_faddr.s_addr;
319 gbeauche 1.5 if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff))
320     saddr.sin_addr.s_addr = alias_addr.s_addr;
321     }
322 gbeauche 1.1 daddr.sin_addr = so->so_laddr;
323     daddr.sin_port = so->so_lport;
324    
325     return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
326     }
327    
328     int
329     udp_attach(so)
330     struct socket *so;
331     {
332     struct sockaddr_in addr;
333    
334     if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
335     /*
336     * Here, we bind() the socket. Although not really needed
337     * (sendto() on an unbound socket will bind it), it's done
338     * here so that emulation of ytalk etc. don't have to do it
339     */
340     addr.sin_family = AF_INET;
341     addr.sin_port = 0;
342     addr.sin_addr.s_addr = INADDR_ANY;
343     if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
344     int lasterrno=errno;
345     closesocket(so->s);
346     so->s=-1;
347     #ifdef _WIN32
348     WSASetLastError(lasterrno);
349     #else
350     errno=lasterrno;
351     #endif
352     } else {
353     /* success, insert in queue */
354     so->so_expire = curtime + SO_EXPIRE;
355     insque(so,&udb);
356     }
357     }
358     return(so->s);
359     }
360    
361     void
362     udp_detach(so)
363     struct socket *so;
364     {
365     closesocket(so->s);
366     /* if (so->so_m) m_free(so->so_m); done by sofree */
367    
368     sofree(so);
369     }
370    
371     struct tos_t udptos[] = {
372     {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */
373     {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */
374     {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */
375     {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */
376     {0, 0, 0, 0}
377     };
378    
379     u_int8_t
380     udp_tos(so)
381     struct socket *so;
382     {
383     int i = 0;
384    
385     while(udptos[i].tos) {
386     if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
387     (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
388     so->so_emu = udptos[i].emu;
389     return udptos[i].tos;
390     }
391     i++;
392     }
393    
394     return 0;
395     }
396    
397     #ifdef EMULATE_TALK
398     #include "talkd.h"
399     #endif
400    
401     /*
402     * Here, talk/ytalk/ntalk requests must be emulated
403     */
404     void
405     udp_emu(so, m)
406     struct socket *so;
407     struct mbuf *m;
408     {
409     struct sockaddr_in addr;
410 cebix 1.3 socklen_t addrlen = sizeof(addr);
411 gbeauche 1.1 #ifdef EMULATE_TALK
412     CTL_MSG_OLD *omsg;
413     CTL_MSG *nmsg;
414     char buff[sizeof(CTL_MSG)];
415     u_char type;
416    
417     struct talk_request {
418     struct talk_request *next;
419     struct socket *udp_so;
420     struct socket *tcp_so;
421     } *req;
422    
423     static struct talk_request *req_tbl = 0;
424    
425     #endif
426    
427     struct cu_header {
428 gbeauche 1.2 uint16_t d_family; // destination family
429     uint16_t d_port; // destination port
430     uint32_t d_addr; // destination address
431     uint16_t s_family; // source family
432     uint16_t s_port; // source port
433 gbeauche 1.4 uint32_t so_addr; // source address
434 gbeauche 1.2 uint32_t seqn; // sequence number
435     uint16_t message; // message
436     uint16_t data_type; // data type
437     uint16_t pkt_len; // packet length
438 gbeauche 1.1 } *cu_head;
439    
440     switch(so->so_emu) {
441    
442     #ifdef EMULATE_TALK
443     case EMU_TALK:
444     case EMU_NTALK:
445     /*
446     * Talk emulation. We always change the ctl_addr to get
447     * some answers from the daemon. When an ANNOUNCE comes,
448     * we send LEAVE_INVITE to the local daemons. Also when a
449     * DELETE comes, we send copies to the local daemons.
450     */
451     if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
452     return;
453    
454     #define IS_OLD (so->so_emu == EMU_TALK)
455    
456     #define COPY_MSG(dest, src) { dest->type = src->type; \
457     dest->id_num = src->id_num; \
458     dest->pid = src->pid; \
459     dest->addr = src->addr; \
460     dest->ctl_addr = src->ctl_addr; \
461     memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
462     memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
463     memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
464    
465     #define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
466     /* old_sockaddr to sockaddr_in */
467    
468    
469     if (IS_OLD) { /* old talk */
470     omsg = mtod(m, CTL_MSG_OLD*);
471     nmsg = (CTL_MSG *) buff;
472     type = omsg->type;
473     OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
474     OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
475     strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD);
476     } else { /* new talk */
477     omsg = (CTL_MSG_OLD *) buff;
478     nmsg = mtod(m, CTL_MSG *);
479     type = nmsg->type;
480     OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
481     OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
482     strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD);
483     }
484    
485     if (type == LOOK_UP)
486     return; /* for LOOK_UP this is enough */
487    
488     if (IS_OLD) { /* make a copy of the message */
489     COPY_MSG(nmsg, omsg);
490     nmsg->vers = 1;
491     nmsg->answer = 0;
492     } else
493     COPY_MSG(omsg, nmsg);
494    
495     /*
496     * If if is an ANNOUNCE message, we go through the
497     * request table to see if a tcp port has already
498     * been redirected for this socket. If not, we solisten()
499     * a new socket and add this entry to the table.
500     * The port number of the tcp socket and our IP
501     * are put to the addr field of the message structures.
502     * Then a LEAVE_INVITE is sent to both local daemon
503     * ports, 517 and 518. This is why we have two copies
504     * of the message, one in old talk and one in new talk
505     * format.
506     */
507    
508     if (type == ANNOUNCE) {
509     int s;
510     u_short temp_port;
511    
512     for(req = req_tbl; req; req = req->next)
513     if (so == req->udp_so)
514     break; /* found it */
515    
516     if (!req) { /* no entry for so, create new */
517     req = (struct talk_request *)
518     malloc(sizeof(struct talk_request));
519     req->udp_so = so;
520     req->tcp_so = solisten(0,
521     OTOSIN(omsg, addr)->sin_addr.s_addr,
522     OTOSIN(omsg, addr)->sin_port,
523     SS_FACCEPTONCE);
524     req->next = req_tbl;
525     req_tbl = req;
526     }
527    
528     /* replace port number in addr field */
529     addrlen = sizeof(addr);
530     getsockname(req->tcp_so->s,
531     (struct sockaddr *) &addr,
532     &addrlen);
533     OTOSIN(omsg, addr)->sin_port = addr.sin_port;
534     OTOSIN(omsg, addr)->sin_addr = our_addr;
535     OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
536     OTOSIN(nmsg, addr)->sin_addr = our_addr;
537    
538     /* send LEAVE_INVITEs */
539     temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
540     OTOSIN(omsg, ctl_addr)->sin_port = 0;
541     OTOSIN(nmsg, ctl_addr)->sin_port = 0;
542     omsg->type = nmsg->type = LEAVE_INVITE;
543    
544     s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
545     addr.sin_addr = our_addr;
546     addr.sin_family = AF_INET;
547     addr.sin_port = htons(517);
548     sendto(s, (char *)omsg, sizeof(*omsg), 0,
549     (struct sockaddr *)&addr, sizeof(addr));
550     addr.sin_port = htons(518);
551     sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
552     (struct sockaddr *) &addr, sizeof(addr));
553     closesocket(s) ;
554    
555     omsg->type = nmsg->type = ANNOUNCE;
556     OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
557     OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
558     }
559    
560     /*
561     * If it is a DELETE message, we send a copy to the
562     * local daemons. Then we delete the entry corresponding
563     * to our socket from the request table.
564     */
565    
566     if (type == DELETE) {
567     struct talk_request *temp_req, *req_next;
568     int s;
569     u_short temp_port;
570    
571     temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
572     OTOSIN(omsg, ctl_addr)->sin_port = 0;
573     OTOSIN(nmsg, ctl_addr)->sin_port = 0;
574    
575     s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
576     addr.sin_addr = our_addr;
577     addr.sin_family = AF_INET;
578     addr.sin_port = htons(517);
579     sendto(s, (char *)omsg, sizeof(*omsg), 0,
580     (struct sockaddr *)&addr, sizeof(addr));
581     addr.sin_port = htons(518);
582     sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
583     (struct sockaddr *)&addr, sizeof(addr));
584     closesocket(s);
585    
586     OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
587     OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
588    
589     /* delete table entry */
590     if (so == req_tbl->udp_so) {
591     temp_req = req_tbl;
592     req_tbl = req_tbl->next;
593     free(temp_req);
594     } else {
595     temp_req = req_tbl;
596     for(req = req_tbl->next; req; req = req_next) {
597     req_next = req->next;
598     if (so == req->udp_so) {
599     temp_req->next = req_next;
600     free(req);
601     break;
602     } else {
603     temp_req = req;
604     }
605     }
606     }
607     }
608    
609     return;
610     #endif
611    
612     case EMU_CUSEEME:
613    
614     /*
615     * Cu-SeeMe emulation.
616     * Hopefully the packet is more that 16 bytes long. We don't
617     * do any other tests, just replace the address and port
618     * fields.
619     */
620     if (m->m_len >= sizeof (*cu_head)) {
621     if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
622     return;
623     cu_head = mtod(m, struct cu_header *);
624 gbeauche 1.2 cu_head->s_port = addr.sin_port;
625 gbeauche 1.4 cu_head->so_addr = our_addr.s_addr;
626 gbeauche 1.1 }
627    
628     return;
629     }
630     }
631    
632     struct socket *
633     udp_listen(port, laddr, lport, flags)
634     u_int port;
635     u_int32_t laddr;
636     u_int lport;
637     int flags;
638     {
639     struct sockaddr_in addr;
640     struct socket *so;
641 cebix 1.3 socklen_t addrlen = sizeof(struct sockaddr_in);
642     int opt = 1;
643 gbeauche 1.1
644     if ((so = socreate()) == NULL) {
645     free(so);
646     return NULL;
647     }
648     so->s = socket(AF_INET,SOCK_DGRAM,0);
649     so->so_expire = curtime + SO_EXPIRE;
650     insque(so,&udb);
651    
652     addr.sin_family = AF_INET;
653     addr.sin_addr.s_addr = INADDR_ANY;
654     addr.sin_port = port;
655    
656     if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
657     udp_detach(so);
658     return NULL;
659     }
660     setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
661     /* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */
662    
663     getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
664     so->so_fport = addr.sin_port;
665     if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
666 gbeauche 1.5 so->so_faddr = alias_addr;
667 gbeauche 1.1 else
668     so->so_faddr = addr.sin_addr;
669    
670     so->so_lport = lport;
671     so->so_laddr.s_addr = laddr;
672     if (flags != SS_FACCEPTONCE)
673     so->so_expire = 0;
674    
675     so->so_state = SS_ISFCONNECTED;
676    
677     return so;
678     }