#include "global.h" #include "udp.h" #include "socket.h" #include "usock.h" static void s_urcall __ARGS((struct iface *iface,struct udp_cb *udp,int cnt)); static void autobind __ARGS((struct usock *up)); static int checkipaddr __ARGS((char *name,int namelen)); int so_udp(up,protocol) struct usock *up; int protocol; { return 0; } int so_udp_bind(up) struct usock *up; { int s; struct sockaddr_in *sp; struct socket lsock; s = up - Usock + SOCKBASE; sp = (struct sockaddr_in *)up->name; lsock.address = sp->sin_addr.s_addr; lsock.port = sp->sin_port; up->cb.udp = open_udp(&lsock,s_urcall); up->cb.udp->user = s; return 0; } int so_udp_conn(up) struct usock *up; { if(up->name == NULLCHAR){ autobind(up); } return 0; } int so_udp_recv(up,bpp,from,fromlen) struct usock *up; struct mbuf **bpp; char *from; int *fromlen; { int cnt; struct udp_cb *udp; struct sockaddr_in *remote; struct socket fsocket; while((udp = up->cb.udp) != NULLUDP && (cnt = recv_udp(udp,&fsocket,bpp)) == -1){ if(up->noblock){ errno = EWOULDBLOCK; return -1; } else if((errno = pwait(up)) != 0){ return -1; } } if(udp == NULLUDP){ /* Connection went away */ errno = ENOTCONN; return -1; } if(from != NULLCHAR && fromlen != (int *)NULL && *fromlen >= SOCKSIZE){ remote = (struct sockaddr_in *)from; remote->sin_family = AF_INET; remote->sin_addr.s_addr = fsocket.address; remote->sin_port = fsocket.port; *fromlen = SOCKSIZE; } return cnt; } int so_udp_send(up,bp,to) struct usock *up; struct mbuf *bp; char *to; { struct sockaddr_in *local,*remote; struct socket lsock,fsock; if(up->name == NULLCHAR) autobind(up); local = (struct sockaddr_in *)up->name; lsock.address = local->sin_addr.s_addr; lsock.port = local->sin_port; if(to != NULLCHAR) { remote = (struct sockaddr_in *)to; } else if(up->peername != NULLCHAR){ remote = (struct sockaddr_in *)up->peername; } else { free_p(bp); errno = ENOTCONN; return -1; } if(checkipaddr(to,up->namelen) == -1){ errno = EAFNOSUPPORT; return -1; } fsock.address = remote->sin_addr.s_addr; fsock.port = remote->sin_port; send_udp(&lsock,&fsock,up->tos,0,bp,0,0,0); return 0; } int so_udp_qlen(up,rtx) struct usock *up; int rtx; { int len; switch(rtx){ case 0: len = up->cb.udp->rcvcnt; break; case 1: len = 0; break; } return len; } int so_udp_close(up) struct usock *up; { if(up->cb.udp != NULLUDP){ del_udp(up->cb.udp); } return 0; } int so_udp_shut(up,how) struct usock *up; int how; { int s; s = up - Usock + SOCKBASE; close_s(s); return 0; } static void s_urcall(iface,udp,cnt) struct iface *iface; struct udp_cb *udp; int cnt; { psignal(itop(udp->user),1); pwait(NULL); } /* Issue an automatic bind of a local address */ static void autobind(up) struct usock *up; { struct sockaddr_in local; int s; s = up - Usock + SOCKBASE; local.sin_family = AF_INET; local.sin_addr.s_addr = INADDR_ANY; local.sin_port = Lport++; bind(s,(char *)&local,sizeof(struct sockaddr_in)); } static int checkipaddr(name,namelen) char *name; int namelen; { struct sockaddr_in *sock; sock = (struct sockaddr_in *)name; if(sock->sin_family != AF_INET || namelen != sizeof(struct sockaddr_in)) return -1; return 0; } int so_udp_stat(up) struct usock *up; { st_udp(up->cb.udp,0); return 0; }