00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef OSCPKT_UDP_HH
00027 #define OSCPKT_UDP_HH
00028
00029 #include <sys/types.h>
00030 #if defined(_MSC_VER) || defined(WIN32)
00031
00032
00033
00034
00035
00036
00037 # include <winsock2.h>
00038 # include <windows.h>
00039 # include <ws2tcpip.h>
00040 # pragma comment(lib, "ws2_32.lib")
00041 #else
00042 # include <sys/socket.h>
00043 # include <netdb.h>
00044 # include <sys/time.h>
00045 #endif
00046 #include <cstring>
00047 #include <cstdio>
00048 #include <cstdlib>
00049 #include <cerrno>
00050 #include <cassert>
00051 #include <string>
00052 #include <vector>
00053
00054 namespace oscpkt {
00055
00056
00057 class SockAddr {
00058 union {
00059 sockaddr_storage ss;
00060 struct sockaddr sa;
00061 } addr_;
00062 public:
00063 struct sockaddr &addr() { return addr_.sa; }
00064 const struct sockaddr &addr() const { return addr_.sa; }
00065 size_t maxLen() const { return sizeof addr_; }
00066 size_t actualLen() const {
00067 if (addr().sa_family == AF_UNSPEC) return 0;
00068 else if (addr().sa_family == AF_INET) return sizeof(struct sockaddr_in);
00069 else if (addr().sa_family == AF_INET6) return sizeof(struct sockaddr_in6);
00070 else return sizeof addr_;
00071 }
00072
00073 SockAddr() { memset(&addr_, 0, sizeof addr_); }
00074 bool empty() const { return addr().sa_family == AF_UNSPEC; }
00075
00076 int getPort() const {
00077 char servname[512];
00078 int err = getnameinfo(&addr_.sa, sizeof addr_, 0, 0, servname, sizeof servname, NI_NUMERICSERV);
00079 return (err == 0 ? atoi(servname) : -1);
00080 }
00081
00082 std::string asString() const {
00083 std::string s;
00084 if (addr().sa_family) {
00085 char hostname[512], servname[512];
00086 int err = getnameinfo(&addr_.sa,
00087 sizeof addr_, hostname, sizeof hostname, servname, sizeof servname, NI_NUMERICHOST|NI_NUMERICSERV);
00088 if (err == 0) {
00089 s = hostname; s += ":"; s += servname;
00090 }
00091 }
00092 return s;
00093 }
00094
00095 friend std::ostream &operator<<(std::ostream &os, const SockAddr &ip) {
00096 os << "[";
00097 switch (ip.addr().sa_family) {
00098 case AF_UNSPEC: os << "AF_UNSPEC"; break;
00099 case AF_INET: os << "IPv4"; break;
00100 case AF_INET6: os << "IPv6"; break;
00101 default: os << "unknown family '" << ip.addr().sa_family << "'"; break;
00102 }
00103 os << " " << ip.asString() << "]";
00104 return os;
00105 }
00106 };
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 struct UdpSocket {
00120 std::string error_message;
00121 int handle;
00122 SockAddr local_addr ;
00123 SockAddr remote_addr;
00124
00125 std::vector<char> buffer;
00126
00127
00128 UdpSocket() : handle(-1) {
00129 #ifdef WIN32
00130 WSADATA wsa_data;
00131 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
00132 setErr("winsock failed to initialise");
00133 }
00134 #endif
00135 }
00136
00137 ~UdpSocket() {
00138 close();
00139 #ifdef WIN32
00140 WSACleanup();
00141 #endif
00142 }
00143
00144 void close() {
00145 if (handle != -1) {
00146 #ifdef WIN32
00147 ::closesocket(handle);
00148 #else
00149 ::close(handle);
00150 #endif
00151 handle = -1;
00152 }
00153 }
00154
00155 bool isOk() const { return error_message.empty(); }
00156 const std::string &errorMessage() const { return error_message; }
00157
00158 bool isBound() const { return !local_addr.empty(); }
00159 int boundPort() const { return local_addr.getPort(); }
00160 std::string boundPortAsString() const {
00161 char s[512];
00162 #ifndef _MSC_VER
00163 snprintf(s, 512, "%d", boundPort());
00164 #else
00165 _snprintf_s(s,512,512, "%d", boundPort());
00166 #endif
00167 return s;
00168 }
00169 int socketHandle() const { return handle; }
00170 std::string localHostName() const {
00171
00172
00173 char hostname_buf[512];
00174 if (gethostname(hostname_buf, sizeof hostname_buf) != 0)
00175 hostname_buf[0] = 0;
00176 hostname_buf[sizeof hostname_buf - 1] = 0;
00177 struct hostent * host = gethostbyname(hostname_buf);
00178 if (host) { return host->h_name; }
00179 return hostname_buf[0] ? hostname_buf : "localhost";
00180 }
00181 std::string localHostNameWithPort() const { return (localHostName() + ":") + boundPortAsString(); }
00182
00183 enum { OPTION_UNSPEC=0, OPTION_FORCE_IPV4=1, OPTION_FORCE_IPV6=2,
00184 OPTION_DEFAULT=OPTION_FORCE_IPV4
00185 };
00186
00187
00188
00189
00190 bool bindTo(int port, int options = OPTION_DEFAULT) {
00191 return openSocket("", port, options);
00192 }
00193
00194
00195 bool connectTo(const std::string &host, const std::string &port, int options = OPTION_DEFAULT) {
00196 return openSocket(host, port, options);
00197 }
00198 bool connectTo(const std::string &host, int port, int options = OPTION_DEFAULT) {
00199 return openSocket(host, port, options);
00200 }
00201
00202 void setErr(const std::string &msg) {
00203 if (error_message.empty()) error_message = msg;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213 bool receiveNextPacket(int timeout_ms = -1) {
00214 if (!isOk() || handle == -1) { setErr("not opened.."); return false; }
00215
00216
00217 buffer.resize(1024*128);
00218
00219
00220 if (timeout_ms >= 0) {
00221 struct timeval tv; memset(&tv, 0, sizeof tv);
00222 tv.tv_sec=timeout_ms/1000;
00223 tv.tv_usec=(timeout_ms%1000) * 1000;
00224
00225
00226
00227 fd_set readset;
00228 FD_ZERO(&readset);
00229 FD_SET(handle, &readset);
00230
00231 int ret = select( handle+1, &readset, 0, 0, &tv );
00232 if (ret <= 0) {
00233 return false;
00234 }
00235 }
00236
00237
00238 socklen_t len = remote_addr.maxLen();
00239 int nread = (int)recvfrom(handle, &buffer[0], buffer.size(), 0,
00240 &remote_addr.addr(), &len);
00241 if (nread < 0) {
00242
00243 #ifdef WIN32
00244 if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK &&
00245 WSAGetLastError() != WSAECONNRESET && WSAGetLastError() != WSAECONNREFUSED) {
00246 char s[512]; _snprintf_s(s,512,512, "system error #%d", WSAGetLastError());
00247 setErr(s);
00248 }
00249 #else
00250 if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK &&
00251 errno != ECONNRESET && errno != ECONNREFUSED) {
00252 setErr(strerror(errno));
00253 }
00254 #endif
00255 if (!isOk()) close();
00256 return false;
00257 }
00258 if (nread > (int)buffer.size()) {
00259
00260 buffer.clear();
00261 } else {
00262 buffer.resize(nread);
00263 std::vector<char> tmp(buffer); tmp.swap(buffer);
00264 }
00265 return true;
00266 }
00267
00268 void *packetData() { return buffer.empty() ? 0 : &buffer[0]; }
00269 size_t packetSize() { return buffer.size(); }
00270 SockAddr &packetOrigin() { return remote_addr; }
00271
00272
00273 bool sendPacket(const void *ptr, size_t sz) {
00274 return sendPacketTo(ptr, sz, remote_addr);
00275 }
00276
00277 bool sendPacketTo(const void *ptr, size_t sz, SockAddr &addr) {
00278 if (!isOk() || handle == -1) { setErr("not opened.."); return false; }
00279 if (!ptr || sz == 0) return false;
00280
00281 int sent = 0;
00282 do {
00283 int res;
00284 if (isBound()) {
00285 res = sendto(handle, (const char*)ptr, sz, 0, &addr.addr(), addr.actualLen());
00286 } else {
00287 res = send(handle, (const char*)ptr, sz, 0);
00288
00289 }
00290 #ifdef WIN32
00291 if (res == -1 && WSAGetLastError() == WSAEINTR) continue;
00292 else sent = res;
00293 #else
00294
00295 if (res == -1 && errno == EINTR) continue;
00296 else sent = res;
00297 #endif
00298 } while (0);
00299
00300 return (size_t)sent == sz;
00301 }
00302
00303 private:
00304 bool openSocket(const std::string &hostname, int port, int options) {
00305 char port_string[64];
00306 #ifdef WIN32
00307 _snprintf_s(port_string, 64, 64, "%d", port);
00308 #else
00309 snprintf(port_string, 64, "%d", port);
00310 #endif
00311 return openSocket(hostname, port_string, options);
00312 }
00313
00314 bool openSocket(const std::string &hostname, const std::string &port, int options) {
00315 bool binding = hostname.empty();
00316 close(); error_message.clear();
00317
00318 struct addrinfo hints;
00319 struct addrinfo *result = 0, *rp = 0;
00320
00321 memset(&hints, 0, sizeof(struct addrinfo));
00322 if (options == OPTION_FORCE_IPV4) hints.ai_family = AF_INET;
00323 else if (options == OPTION_FORCE_IPV6) hints.ai_family = AF_INET6;
00324 else hints.ai_family = AF_UNSPEC;
00325 hints.ai_socktype = SOCK_DGRAM;
00326 hints.ai_flags = (binding ? AI_PASSIVE : 0);
00327
00328 int err = 0;
00329
00330
00331 err = getaddrinfo(binding ? 0 : hostname.c_str(), port.empty() ? 0 : port.c_str(), &hints, &result);
00332 if (err != 0) {
00333 setErr(gai_strerror(err));
00334 return false;
00335 }
00336
00337 for (rp = result; rp && handle==-1; rp = rp->ai_next) {
00338
00339
00340 handle = socket(rp->ai_family, rp->ai_socktype,
00341 rp->ai_protocol);
00342 if (handle == -1)
00343 continue;
00344
00345 if (binding) {
00346 if (bind(handle, rp->ai_addr, rp->ai_addrlen) != 0) {
00347 close();
00348 } else {
00349 socklen_t len = local_addr.maxLen();
00350 if (getsockname(handle, &local_addr.addr(), &len) == 0) {
00351
00352 }
00353 break;
00354 }
00355 } else {
00356 if (connect(handle, rp->ai_addr, rp->ai_addrlen) != 0) {
00357 close();
00358 } else {
00359 assert(rp->ai_addrlen <= sizeof remote_addr);
00360 memcpy(&remote_addr.addr(), rp->ai_addr, rp->ai_addrlen);
00361 break;
00362 }
00363 }
00364 }
00365
00366
00367 freeaddrinfo(result); result = 0;
00368
00369 if (!rp) {
00370 setErr(binding ? "bind failed" : "connect failed"); assert(handle == -1);
00371 return false;
00372 }
00373 return true;
00374 }
00375 };
00376
00377
00378 struct Url {
00379 std::string protocol;
00380 std::string hostname;
00381 std::string port;
00382 std::string path;
00383 int err;
00384 Url() : err(0) {}
00385 Url(const std::string &url) { init(url); }
00386 bool isOk() const { return err == 0; }
00387 bool init(const std::string &url) {
00388 err = 0;
00389 const char *s = url.c_str();
00390 const char *prot = strstr(s, "osc.");
00391 if (prot == 0) { protocol = "udp"; }
00392 else {
00393 const char *p2 = strstr(prot, "://");
00394 if (p2) { protocol.assign(prot+4, p2); }
00395 else { err = 1; return false; }
00396 s = p2+3;
00397 }
00398 const char *po = strstr(s, ":");
00399 if (!po) { err = 2; return false; }
00400 hostname.assign(s, po);
00401 s = po+1;
00402
00403 const char *pa = strstr(s, "/");
00404 if (!pa) { port = s; path = "/"; }
00405 else { port.assign(s, pa); path = pa; }
00406 return true;
00407 }
00408 };
00409
00410
00411 }
00412
00413 #endif // OSCPKT_UDP_HH