WvStreams
|
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 }