00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifdef _WIN32
00031 #pragma warning(disable:4786)
00032 #include <stdlib.h>
00033 #else
00034 #include <errno.h>
00035 #endif
00036
00037 #include "ISocketHandler.h"
00038 #include "UdpSocket.h"
00039 #include "Utility.h"
00040 #include "Ipv4Address.h"
00041 #include "Ipv6Address.h"
00042
00043
00044
00045
00046 #ifdef SOCKETS_NAMESPACE
00047 namespace SOCKETS_NAMESPACE {
00048 #endif
00049
00050
00051 UdpSocket::UdpSocket(ISocketHandler& h, int ibufsz, bool ipv6) : Socket(h)
00052 , m_ibuf(new char[ibufsz])
00053 , m_ibufsz(ibufsz)
00054 , m_bind_ok(false)
00055 , m_port(0)
00056 , m_last_size_written(-1)
00057 {
00058 #ifdef ENABLE_IPV6
00059 #ifdef IPPROTO_IPV6
00060 SetIpv6(ipv6);
00061 #endif
00062 #endif
00063 }
00064
00065
00066 UdpSocket::~UdpSocket()
00067 {
00068 Close();
00069 delete[] m_ibuf;
00070 }
00071
00072
00073 int UdpSocket::Bind(port_t &port, int range)
00074 {
00075 #ifdef ENABLE_IPV6
00076 #ifdef IPPROTO_IPV6
00077 if (IsIpv6())
00078 {
00079 Ipv6Address ad(port);
00080 return Bind(ad, range);
00081 }
00082 #endif
00083 #endif
00084 Ipv4Address ad(port);
00085 return Bind(ad, range);
00086 }
00087
00088
00089 int UdpSocket::Bind(const std::string& intf, port_t &port, int range)
00090 {
00091 #ifdef ENABLE_IPV6
00092 #ifdef IPPROTO_IPV6
00093 if (IsIpv6())
00094 {
00095 Ipv6Address ad(intf, port);
00096 if (ad.IsValid())
00097 {
00098 return Bind(ad, range);
00099 }
00100 SetCloseAndDelete();
00101 return -1;
00102 }
00103 #endif
00104 #endif
00105 Ipv4Address ad(intf, port);
00106 if (ad.IsValid())
00107 {
00108 return Bind(ad, range);
00109 }
00110 SetCloseAndDelete();
00111 return -1;
00112 }
00113
00114
00115 int UdpSocket::Bind(ipaddr_t a, port_t &port, int range)
00116 {
00117 Ipv4Address ad(a, port);
00118 return Bind(ad, range);
00119 }
00120
00121
00122 #ifdef ENABLE_IPV6
00123 #ifdef IPPROTO_IPV6
00124 int UdpSocket::Bind(in6_addr a, port_t &port, int range)
00125 {
00126 Ipv6Address ad(a, port);
00127 return Bind(ad, range);
00128 }
00129 #endif
00130 #endif
00131
00132
00133 int UdpSocket::Bind(SocketAddress& ad, int range)
00134 {
00135 if (GetSocket() == INVALID_SOCKET)
00136 {
00137 Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
00138 }
00139 if (GetSocket() != INVALID_SOCKET)
00140 {
00141 SetNonblocking(true);
00142 int n = bind(GetSocket(), ad, ad);
00143 int tries = range;
00144 while (n == -1 && tries--)
00145 {
00146 ad.SetPort(ad.GetPort() + 1);
00147 n = bind(GetSocket(), ad, ad);
00148 }
00149 if (n == -1)
00150 {
00151 Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL);
00152 SetCloseAndDelete();
00153 return -1;
00154 }
00155 m_bind_ok = true;
00156 m_port = ad.GetPort();
00157 return 0;
00158 }
00159 return -1;
00160 }
00161
00162
00164 bool UdpSocket::Open(ipaddr_t l, port_t port)
00165 {
00166 Ipv4Address ad(l, port);
00167 return Open(ad);
00168 }
00169
00170
00171 bool UdpSocket::Open(const std::string& host, port_t port)
00172 {
00173 #ifdef ENABLE_IPV6
00174 #ifdef IPPROTO_IPV6
00175 if (IsIpv6())
00176 {
00177 Ipv6Address ad(host, port);
00178 if (ad.IsValid())
00179 {
00180 return Open(ad);
00181 }
00182 return false;
00183 }
00184 #endif
00185 #endif
00186 Ipv4Address ad(host, port);
00187 if (ad.IsValid())
00188 {
00189 return Open(ad);
00190 }
00191 return false;
00192 }
00193
00194
00195 #ifdef ENABLE_IPV6
00196 #ifdef IPPROTO_IPV6
00197 bool UdpSocket::Open(struct in6_addr& a, port_t port)
00198 {
00199 Ipv6Address ad(a, port);
00200 return Open(ad);
00201 }
00202 #endif
00203 #endif
00204
00205
00206 bool UdpSocket::Open(SocketAddress& ad)
00207 {
00208 if (GetSocket() == INVALID_SOCKET)
00209 {
00210 Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
00211 }
00212 if (GetSocket() != INVALID_SOCKET)
00213 {
00214 SetNonblocking(true);
00215 if (connect(GetSocket(), ad, ad) == -1)
00216 {
00217 Handler().LogError(this, "connect", Errno, StrError(Errno), LOG_LEVEL_FATAL);
00218 SetCloseAndDelete();
00219 return false;
00220 }
00221 SetConnected();
00222 return true;
00223 }
00224 return false;
00225 }
00226
00227
00228 void UdpSocket::CreateConnection()
00229 {
00230 #ifdef ENABLE_IPV6
00231 #ifdef IPPROTO_IPV6
00232 if (IsIpv6())
00233 {
00234 if (GetSocket() == INVALID_SOCKET)
00235 {
00236 SOCKET s = CreateSocket(AF_INET6, SOCK_DGRAM, "udp");
00237 if (s == INVALID_SOCKET)
00238 {
00239 return;
00240 }
00241 SetNonblocking(true, s);
00242 Attach(s);
00243 }
00244 return;
00245 }
00246 #endif
00247 #endif
00248 if (GetSocket() == INVALID_SOCKET)
00249 {
00250 SOCKET s = CreateSocket(AF_INET, SOCK_DGRAM, "udp");
00251 if (s == INVALID_SOCKET)
00252 {
00253 return;
00254 }
00255 SetNonblocking(true, s);
00256 Attach(s);
00257 }
00258 }
00259
00260
00262 void UdpSocket::SendToBuf(const std::string& h, port_t p, const char *data, int len, int flags)
00263 {
00264 #ifdef ENABLE_IPV6
00265 #ifdef IPPROTO_IPV6
00266 if (IsIpv6())
00267 {
00268 Ipv6Address ad(h, p);
00269 if (ad.IsValid())
00270 {
00271 SendToBuf(ad, data, len, flags);
00272 }
00273 return;
00274 }
00275 #endif
00276 #endif
00277 Ipv4Address ad(h, p);
00278 if (ad.IsValid())
00279 {
00280 SendToBuf(ad, data, len, flags);
00281 }
00282 }
00283
00284
00286 void UdpSocket::SendToBuf(ipaddr_t a, port_t p, const char *data, int len, int flags)
00287 {
00288 Ipv4Address ad(a, p);
00289 SendToBuf(ad, data, len, flags);
00290 }
00291
00292
00293 #ifdef ENABLE_IPV6
00294 #ifdef IPPROTO_IPV6
00295 void UdpSocket::SendToBuf(in6_addr a, port_t p, const char *data, int len, int flags)
00296 {
00297 Ipv6Address ad(a, p);
00298 SendToBuf(ad, data, len, flags);
00299 }
00300 #endif
00301 #endif
00302
00303
00304 void UdpSocket::SendToBuf(SocketAddress& ad, const char *data, int len, int flags)
00305 {
00306 if (GetSocket() == INVALID_SOCKET)
00307 {
00308 Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
00309 }
00310 if (GetSocket() != INVALID_SOCKET)
00311 {
00312 SetNonblocking(true);
00313 if ((m_last_size_written = sendto(GetSocket(), data, len, flags, ad, ad)) == -1)
00314 {
00315 Handler().LogError(this, "sendto", Errno, StrError(Errno), LOG_LEVEL_ERROR);
00316 }
00317 }
00318 }
00319
00320
00321 void UdpSocket::SendTo(const std::string& a, port_t p, const std::string& str, int flags)
00322 {
00323 SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
00324 }
00325
00326
00327 void UdpSocket::SendTo(ipaddr_t a, port_t p, const std::string& str, int flags)
00328 {
00329 SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
00330 }
00331
00332
00333 #ifdef ENABLE_IPV6
00334 #ifdef IPPROTO_IPV6
00335 void UdpSocket::SendTo(in6_addr a, port_t p, const std::string& str, int flags)
00336 {
00337 SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
00338 }
00339 #endif
00340 #endif
00341
00342
00343 void UdpSocket::SendTo(SocketAddress& ad, const std::string& str, int flags)
00344 {
00345 SendToBuf(ad, str.c_str(), (int)str.size(), flags);
00346 }
00347
00348
00350 void UdpSocket::SendBuf(const char *data, size_t len, int flags)
00351 {
00352 if (!IsConnected())
00353 {
00354 Handler().LogError(this, "SendBuf", 0, "not connected", LOG_LEVEL_ERROR);
00355 return;
00356 }
00357 if ((m_last_size_written = send(GetSocket(), data, (int)len, flags)) == -1)
00358 {
00359 Handler().LogError(this, "send", Errno, StrError(Errno), LOG_LEVEL_ERROR);
00360 }
00361 }
00362
00363
00364 void UdpSocket::Send(const std::string& str, int flags)
00365 {
00366 SendBuf(str.c_str(), (int)str.size(), flags);
00367 }
00368
00369
00370 void UdpSocket::OnRead()
00371 {
00372 #ifdef ENABLE_IPV6
00373 #ifdef IPPROTO_IPV6
00374 if (IsIpv6())
00375 {
00376 struct sockaddr_in6 sa;
00377 socklen_t sa_len = sizeof(sa);
00378 int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
00379 int q = 10;
00380 while (n > 0)
00381 {
00382 if (sa_len != sizeof(sa))
00383 {
00384 Handler().LogError(this, "recvfrom", 0, "unexpected address struct size", LOG_LEVEL_WARNING);
00385 }
00386 this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len);
00387 if (!q--)
00388 break;
00389
00390 n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
00391 }
00392 if (n == -1)
00393 {
00394 #ifdef _WIN32
00395 if (Errno != WSAEWOULDBLOCK)
00396 #else
00397 if (Errno != EWOULDBLOCK)
00398 #endif
00399 Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR);
00400 }
00401 return;
00402 }
00403 #endif
00404 #endif
00405 struct sockaddr_in sa;
00406 socklen_t sa_len = sizeof(sa);
00407 int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
00408 int q = 10;
00409 while (n > 0)
00410 {
00411 if (sa_len != sizeof(sa))
00412 {
00413 Handler().LogError(this, "recvfrom", 0, "unexpected address struct size", LOG_LEVEL_WARNING);
00414 }
00415 this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len);
00416 if (!q--)
00417 break;
00418
00419 n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
00420 }
00421 if (n == -1)
00422 {
00423 #ifdef _WIN32
00424 if (Errno != WSAEWOULDBLOCK)
00425 #else
00426 if (Errno != EWOULDBLOCK)
00427 #endif
00428 Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR);
00429 }
00430 }
00431
00432
00433 void UdpSocket::SetBroadcast(bool b)
00434 {
00435 int one = 1;
00436 int zero = 0;
00437
00438 if (GetSocket() == INVALID_SOCKET)
00439 {
00440 CreateConnection();
00441 }
00442 if (b)
00443 {
00444 if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof(one)) == -1)
00445 {
00446 Handler().LogError(this, "SetBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00447 }
00448 }
00449 else
00450 {
00451 if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *) &zero, sizeof(zero)) == -1)
00452 {
00453 Handler().LogError(this, "SetBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00454 }
00455 }
00456 }
00457
00458
00459 bool UdpSocket::IsBroadcast()
00460 {
00461 int is_broadcast = 0;
00462 socklen_t size;
00463
00464 if (GetSocket() == INVALID_SOCKET)
00465 {
00466 CreateConnection();
00467 }
00468 if (getsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *)&is_broadcast, &size) == -1)
00469 {
00470 Handler().LogError(this, "IsBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00471 }
00472 return is_broadcast != 0;
00473 }
00474
00475
00476 void UdpSocket::SetMulticastTTL(int ttl)
00477 {
00478 if (GetSocket() == INVALID_SOCKET)
00479 {
00480 CreateConnection();
00481 }
00482 if (setsockopt(GetSocket(), SOL_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(int)) == -1)
00483 {
00484 Handler().LogError(this, "SetMulticastTTL", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00485 }
00486 }
00487
00488
00489 int UdpSocket::GetMulticastTTL()
00490 {
00491 int ttl = 0;
00492 socklen_t size = sizeof(int);
00493
00494 if (GetSocket() == INVALID_SOCKET)
00495 {
00496 CreateConnection();
00497 }
00498 if (getsockopt(GetSocket(), SOL_IP, IP_MULTICAST_TTL, (char *)&ttl, &size) == -1)
00499 {
00500 Handler().LogError(this, "GetMulticastTTL", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00501 }
00502 return ttl;
00503 }
00504
00505
00506 void UdpSocket::SetMulticastLoop(bool x)
00507 {
00508 if (GetSocket() == INVALID_SOCKET)
00509 {
00510 CreateConnection();
00511 }
00512 #ifdef ENABLE_IPV6
00513 #ifdef IPPROTO_IPV6
00514 if (IsIpv6())
00515 {
00516 int val = x ? 1 : 0;
00517 if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&val, sizeof(int)) == -1)
00518 {
00519 Handler().LogError(this, "SetMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00520 }
00521 return;
00522 }
00523 #endif
00524 #endif
00525 int val = x ? 1 : 0;
00526 if (setsockopt(GetSocket(), SOL_IP, IP_MULTICAST_LOOP, (char *)&val, sizeof(int)) == -1)
00527 {
00528 Handler().LogError(this, "SetMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00529 }
00530 }
00531
00532
00533 bool UdpSocket::IsMulticastLoop()
00534 {
00535 if (GetSocket() == INVALID_SOCKET)
00536 {
00537 CreateConnection();
00538 }
00539 #ifdef ENABLE_IPV6
00540 #ifdef IPPROTO_IPV6
00541 if (IsIpv6())
00542 {
00543 int is_loop = 0;
00544 socklen_t size = sizeof(int);
00545 if (getsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&is_loop, &size) == -1)
00546 {
00547 Handler().LogError(this, "IsMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00548 }
00549 return is_loop ? true : false;
00550 }
00551 #endif
00552 #endif
00553 int is_loop = 0;
00554 socklen_t size = sizeof(int);
00555 if (getsockopt(GetSocket(), SOL_IP, IP_MULTICAST_LOOP, (char *)&is_loop, &size) == -1)
00556 {
00557 Handler().LogError(this, "IsMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00558 }
00559 return is_loop ? true : false;
00560 }
00561
00562
00563 void UdpSocket::AddMulticastMembership(const std::string& group, const std::string& local_if, int if_index)
00564 {
00565 if (GetSocket() == INVALID_SOCKET)
00566 {
00567 CreateConnection();
00568 }
00569 #ifdef ENABLE_IPV6
00570 #ifdef IPPROTO_IPV6
00571 if (IsIpv6())
00572 {
00573 struct ipv6_mreq x;
00574 struct in6_addr addr;
00575 if (Utility::u2ip( group, addr ))
00576 {
00577 x.ipv6mr_multiaddr = addr;
00578 x.ipv6mr_interface = if_index;
00579 if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&x, sizeof(struct ipv6_mreq)) == -1)
00580 {
00581 Handler().LogError(this, "AddMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00582 }
00583 }
00584 return;
00585 }
00586 #endif
00587 #endif
00588 struct ip_mreq x;
00589 ipaddr_t addr;
00590 if (Utility::u2ip( group, addr ))
00591 {
00592 memcpy(&x.imr_multiaddr.s_addr, &addr, sizeof(addr));
00593 Utility::u2ip( local_if, addr);
00594 memcpy(&x.imr_interface.s_addr, &addr, sizeof(addr));
00595
00596 if (setsockopt(GetSocket(), SOL_IP, IP_ADD_MEMBERSHIP, (char *)&x, sizeof(struct ip_mreq)) == -1)
00597 {
00598 Handler().LogError(this, "AddMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00599 }
00600 }
00601 }
00602
00603
00604 void UdpSocket::DropMulticastMembership(const std::string& group, const std::string& local_if, int if_index)
00605 {
00606 if (GetSocket() == INVALID_SOCKET)
00607 {
00608 CreateConnection();
00609 }
00610 #ifdef ENABLE_IPV6
00611 #ifdef IPPROTO_IPV6
00612 if (IsIpv6())
00613 {
00614 struct ipv6_mreq x;
00615 struct in6_addr addr;
00616 if (Utility::u2ip( group, addr ))
00617 {
00618 x.ipv6mr_multiaddr = addr;
00619 x.ipv6mr_interface = if_index;
00620 if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *)&x, sizeof(struct ipv6_mreq)) == -1)
00621 {
00622 Handler().LogError(this, "DropMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00623 }
00624 }
00625 return;
00626 }
00627 #endif
00628 #endif
00629 struct ip_mreq x;
00630 ipaddr_t addr;
00631 if (Utility::u2ip( group, addr ))
00632 {
00633 memcpy(&x.imr_multiaddr.s_addr, &addr, sizeof(addr));
00634 Utility::u2ip( local_if, addr);
00635 memcpy(&x.imr_interface.s_addr, &addr, sizeof(addr));
00636
00637 if (setsockopt(GetSocket(), SOL_IP, IP_DROP_MEMBERSHIP, (char *)&x, sizeof(struct ip_mreq)) == -1)
00638 {
00639 Handler().LogError(this, "DropMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00640 }
00641 }
00642 }
00643
00644
00645 #ifdef ENABLE_IPV6
00646 #ifdef IPPROTO_IPV6
00647 void UdpSocket::SetMulticastHops(int hops)
00648 {
00649 if (GetSocket() == INVALID_SOCKET)
00650 {
00651 CreateConnection();
00652 }
00653 if (!IsIpv6())
00654 {
00655 Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR);
00656 return;
00657 }
00658 if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hops, sizeof(int)) == -1)
00659 {
00660 Handler().LogError(this, "SetMulticastHops", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00661 }
00662 }
00663
00664
00665 int UdpSocket::GetMulticastHops()
00666 {
00667 if (GetSocket() == INVALID_SOCKET)
00668 {
00669 CreateConnection();
00670 }
00671 if (!IsIpv6())
00672 {
00673 Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR);
00674 return -1;
00675 }
00676 int hops = 0;
00677 socklen_t size = sizeof(int);
00678 if (getsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hops, &size) == -1)
00679 {
00680 Handler().LogError(this, "GetMulticastHops", Errno, StrError(Errno), LOG_LEVEL_WARNING);
00681 }
00682 return hops;
00683 }
00684 #endif // IPPROTO_IPV6
00685 #endif
00686
00687
00688 bool UdpSocket::IsBound()
00689 {
00690 return m_bind_ok;
00691 }
00692
00693
00694 void UdpSocket::OnRawData(const char *buf, size_t len, struct sockaddr *sa, socklen_t sa_len)
00695 {
00696 }
00697
00698
00699 port_t UdpSocket::GetPort()
00700 {
00701 return m_port;
00702 }
00703
00704
00705 int UdpSocket::GetLastSizeWritten()
00706 {
00707 return m_last_size_written;
00708 }
00709
00710
00711 #ifdef SOCKETS_NAMESPACE
00712 }
00713 #endif
00714