WvStreams
wvudp.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvUDPStream can send and receive packets on a connectionless UDP socket.
00006  * See wvudp.h for details.
00007  */
00008 #include "wvudp.h"
00009 
00010 #ifndef WIN32
00011 #include <sys/socket.h>
00012 #else
00013 #define setsockopt(a,b,c,d,e) setsockopt(a,b,c, (const char*) d,e)
00014 #define recvfrom(a,b,c,d,e,f) recvfrom(a, (char *) b, c, d, e, f)
00015 #define sendto(a,b,c,d,e,f) sendto(a,(const char*) b,c,d,e,f)
00016 #undef errno
00017 #define errno GetLastError()
00018 #endif
00019 
00020 #include <fcntl.h>
00021 
00022 #ifdef ISDARWIN
00023 # define socklen_t int
00024 #endif
00025 
00026 WvUDPStream::WvUDPStream(const WvIPPortAddr &_local,
00027     const WvIPPortAddr &_rem) :
00028     localaddr(), remaddr(_rem)
00029 {
00030     int x = 1;
00031     setfd(socket(PF_INET, SOCK_DGRAM, 0));
00032     if (getfd() < 0 
00033         || setsockopt(getfd(), SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)) < 0)
00034     {
00035         seterr(errno);
00036         return;
00037     }
00038     
00039     set_close_on_exec(true);
00040     set_nonblock(true);
00041 
00042     struct sockaddr *sa = _local.sockaddr();
00043     if (bind(getfd(), sa, _local.sockaddr_len()))
00044     {
00045         delete sa;
00046         seterr(errno);
00047         return;
00048     }
00049     delete sa;
00050     
00051     struct sockaddr_in nsa;
00052     socklen_t nsalen = sizeof(nsa);
00053     if (getsockname(getfd(), (sockaddr *)&nsa, &nsalen) < 0)
00054     {
00055         seterr(errno);
00056         return;
00057     }
00058     localaddr = WvIPPortAddr(&nsa);
00059     
00060     if (WvIPAddr(_rem) != WvIPAddr())
00061     {
00062         struct sockaddr *sa = _rem.sockaddr();
00063         if (connect(getfd(), sa, _rem.sockaddr_len()))
00064         {
00065             delete sa;
00066             seterr(errno);
00067             return;
00068         }
00069         delete sa;
00070     }
00071 }
00072 
00073 
00074 WvUDPStream::~WvUDPStream()
00075 {
00076 }
00077 
00078 
00079 const WvAddr *WvUDPStream::src() const
00080 {
00081     return &remaddr;
00082 }
00083 
00084 
00085 const WvAddr *WvUDPStream::local() const
00086 {
00087     return &localaddr;
00088 }
00089 
00090 
00091 size_t WvUDPStream::uread(void *buf, size_t count)
00092 {
00093     if (!isok() || !buf || !count) return 0;
00094     
00095     struct sockaddr_in from;
00096     socklen_t fromlen = sizeof(from);
00097     int in = recvfrom(getfd(), buf, count, 0, (sockaddr *)&from, &fromlen);
00098     
00099     if (in >= 0)
00100         remaddr = WvIPPortAddr(&from);
00101 
00102     // errors in UDP are ignored
00103     return in < 0 ? 0 : in;
00104 }
00105 
00106 
00107 size_t WvUDPStream::uwrite(const void *buf, size_t count)
00108 {
00109     if (!isok() || !buf || !count) return 0;
00110      
00111     // pretend everything worked if there is nowhere to send data
00112     if (remaddr.is_zero()) return count;
00113     
00114     struct sockaddr *to = remaddr.sockaddr();
00115     size_t tolen = remaddr.sockaddr_len();
00116     int out;
00117     
00118     out = sendto(getfd(), buf, count, 0, to, tolen);
00119     
00120     if (out < 0 && errno == EACCES) // permission denied
00121         seterr(EACCES);
00122     
00123     delete to;
00124     
00125     // errors in UDP are ignored
00126     // pretend that the write always succeeds even if the kernel
00127     // complains since we don't want datagrams backing up in the
00128     // buffer and forming merged datagrams as a result
00129     return out < 0 ? 0 : out;
00130 }
00131 
00132 
00133 void WvUDPStream::enable_broadcasts()
00134 {
00135     int value = 1;
00136     
00137     if (!isok()) return;
00138     
00139     setsockopt(getfd(), SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
00140 }