ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/socket.c
Revision: 1.2
Committed: 2005-06-30T21:25:26Z (18 years, 10 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-17
Changes since 1.1: +4 -2 lines
Log Message:
minor cleanups

File Contents

# User Rev Content
1 gbeauche 1.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 cebix 1.2 socklen_t addrlen = sizeof(struct sockaddr_in);
389 gbeauche 1.1
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 cebix 1.2 int s;
542     socklen_t addrlen = sizeof(addr);
543     int opt = 1;
544 gbeauche 1.1
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