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