├── .gitignore ├── LICENSE ├── README.md ├── include └── Socket.hpp └── test ├── Makefile ├── main.cpp ├── test.sln ├── test.vcxproj ├── test.vcxproj.filters └── test.xcodeproj ├── project.pbxproj └── project.xcworkspace └── contents.xcworkspacedata /.gitignore: -------------------------------------------------------------------------------- 1 | test/test.xcodeproj/project.xcworkspace/xcshareddata 2 | test/test.xcodeproj/project.xcworkspace/xcuserdata 3 | test/test.xcodeproj/xcshareddata 4 | test/test.xcodeproj/xcuserdata 5 | test/Debug/ 6 | test/Release/ 7 | test/x64/ 8 | test/test.opensdf 9 | test/test.sdf 10 | *.opendb 11 | *.db 12 | *.o 13 | test/test 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Elviss Strazdiņš 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cppsocket 2 | C++ socket wrapper 3 | -------------------------------------------------------------------------------- /include/Socket.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // cppsocket 3 | // 4 | 5 | #ifndef CPPSOCKET_HPP 6 | #define CPPSOCKET_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #ifdef _WIN32 19 | # pragma push_macro("WIN32_LEAN_AND_MEAN") 20 | # pragma push_macro("NOMINMAX") 21 | # ifndef WIN32_LEAN_AND_MEAN 22 | # define WIN32_LEAN_AND_MEAN 23 | # endif 24 | # ifndef NOMINMAX 25 | # define NOMINMAX 26 | # endif 27 | # include 28 | # include 29 | # pragma pop_macro("WIN32_LEAN_AND_MEAN") 30 | # pragma pop_macro("NOMINMAX") 31 | #else 32 | # include 33 | # include 34 | # include 35 | # include 36 | # include 37 | #endif 38 | #include 39 | #include 40 | 41 | namespace cppsocket 42 | { 43 | #ifdef _WIN32 44 | using socket_t = SOCKET; 45 | static constexpr socket_t NULL_SOCKET = INVALID_SOCKET; 46 | #else 47 | using socket_t = int; 48 | static constexpr socket_t NULL_SOCKET = -1; 49 | #endif 50 | 51 | static constexpr uint32_t ANY_ADDRESS = 0; 52 | static constexpr uint16_t ANY_PORT = 0; 53 | static constexpr int WAITING_QUEUE_SIZE = 5; 54 | 55 | inline std::string ipToString(uint32_t ip) 56 | { 57 | uint8_t* ptr = reinterpret_cast(&ip); 58 | 59 | return std::to_string(static_cast(ptr[0])) + "." + 60 | std::to_string(static_cast(ptr[1])) + "." + 61 | std::to_string(static_cast(ptr[2])) + "." + 62 | std::to_string(static_cast(ptr[3])); 63 | } 64 | 65 | #ifdef _WIN32 66 | class WinSock final 67 | { 68 | public: 69 | WinSock(): 70 | version(start(MAKEWORD(2, 2))) 71 | { 72 | } 73 | 74 | ~WinSock() 75 | { 76 | if (version) WSACleanup(); 77 | } 78 | 79 | WinSock(const WinSock& other): 80 | version(other.version ? start(other.version) : 0) 81 | { 82 | } 83 | 84 | WinSock& operator=(const WinSock& other) 85 | { 86 | if (&other == this) return *this; 87 | if (version != other.version) 88 | { 89 | if (version) 90 | { 91 | WSACleanup(); 92 | version = 0; 93 | } 94 | 95 | if (other.version) version = start(other.version); 96 | } 97 | } 98 | 99 | WinSock(WinSock&& other) noexcept: 100 | version(other.version) 101 | { 102 | other.version = 0; 103 | } 104 | 105 | WinSock& operator=(WinSock&& other) noexcept 106 | { 107 | if (&other == this) return *this; 108 | if (version) WSACleanup(); 109 | version = other.version; 110 | other.version = 0; 111 | return *this; 112 | } 113 | 114 | private: 115 | static WORD start(WORD version) 116 | { 117 | WSADATA wsaData; 118 | const int error = WSAStartup(version, &wsaData); 119 | if (error != 0) 120 | throw std::system_error(error, std::system_category(), "WSAStartup failed"); 121 | 122 | if (wsaData.wVersion != version) 123 | { 124 | WSACleanup(); 125 | throw std::runtime_error("Invalid WinSock version"); 126 | } 127 | 128 | return wsaData.wVersion; 129 | } 130 | 131 | WORD version = 0; 132 | }; 133 | #endif 134 | 135 | inline int getLastError() noexcept 136 | { 137 | #ifdef _WIN32 138 | return WSAGetLastError(); 139 | #else 140 | return errno; 141 | #endif 142 | } 143 | 144 | inline std::pair getAddress(const std::string& address) 145 | { 146 | std::pair result(ANY_ADDRESS, ANY_PORT); 147 | 148 | size_t i = address.find(':'); 149 | std::string addressStr; 150 | std::string portStr; 151 | 152 | if (i != std::string::npos) 153 | { 154 | addressStr = address.substr(0, i); 155 | portStr = address.substr(i + 1); 156 | } 157 | else 158 | addressStr = address; 159 | 160 | addrinfo* info; 161 | int ret = getaddrinfo(addressStr.c_str(), portStr.empty() ? nullptr : portStr.c_str(), nullptr, &info); 162 | 163 | if (ret != 0) 164 | throw std::system_error(getLastError(), std::system_category(), "Failed to get address info of " + address); 165 | 166 | sockaddr_in* addr = reinterpret_cast(info->ai_addr); 167 | result.first = addr->sin_addr.s_addr; 168 | result.second = ntohs(addr->sin_port); 169 | 170 | freeaddrinfo(info); 171 | 172 | return result; 173 | } 174 | 175 | class Network; 176 | 177 | class Socket final 178 | { 179 | friend Network; 180 | public: 181 | Socket(Network& aNetwork); 182 | ~Socket(); 183 | 184 | Socket(const Socket&) = delete; 185 | Socket& operator=(const Socket&) = delete; 186 | 187 | Socket(Socket&& other); 188 | Socket& operator=(Socket&& other) 189 | { 190 | if (&other != this) 191 | { 192 | closeSocketFd(); 193 | 194 | socketFd = other.socketFd; 195 | ready = other.ready; 196 | blocking = other.blocking; 197 | localAddress = other.localAddress; 198 | localPort = other.localPort; 199 | remoteAddress = other.remoteAddress; 200 | remotePort = other.remotePort; 201 | connectTimeout = other.connectTimeout; 202 | timeSinceConnect = other.timeSinceConnect; 203 | accepting = other.accepting; 204 | connecting = other.connecting; 205 | readCallback = std::move(other.readCallback); 206 | closeCallback = std::move(other.closeCallback); 207 | acceptCallback = std::move(other.acceptCallback); 208 | connectCallback = std::move(other.connectCallback); 209 | connectErrorCallback = std::move(other.connectErrorCallback); 210 | outData = std::move(other.outData); 211 | 212 | remoteAddressString = ipToString(remoteAddress) + ":" + std::to_string(remotePort); 213 | 214 | other.socketFd = NULL_SOCKET; 215 | other.ready = false; 216 | other.blocking = true; 217 | other.localAddress = 0; 218 | other.localPort = 0; 219 | other.remoteAddress = 0; 220 | other.remotePort = 0; 221 | other.accepting = false; 222 | other.connecting = false; 223 | other.connectTimeout = 10.0f; 224 | other.timeSinceConnect = 0.0f; 225 | } 226 | 227 | return *this; 228 | } 229 | 230 | void close() 231 | { 232 | if (socketFd != NULL_SOCKET) 233 | { 234 | if (ready) 235 | { 236 | try 237 | { 238 | writeData(); 239 | } 240 | catch (...) 241 | { 242 | } 243 | } 244 | 245 | closeSocketFd(); 246 | } 247 | 248 | localAddress = 0; 249 | localPort = 0; 250 | remoteAddress = 0; 251 | remotePort = 0; 252 | ready = false; 253 | accepting = false; 254 | connecting = false; 255 | outData.clear(); 256 | inData.clear(); 257 | } 258 | 259 | void update(float delta) 260 | { 261 | if (connecting) 262 | { 263 | timeSinceConnect += delta; 264 | 265 | if (timeSinceConnect > connectTimeout) 266 | { 267 | connecting = false; 268 | 269 | close(); 270 | 271 | if (connectErrorCallback) 272 | connectErrorCallback(*this); 273 | } 274 | } 275 | } 276 | 277 | void startRead() 278 | { 279 | if (socketFd == NULL_SOCKET) 280 | throw std::runtime_error("Can not start reading, invalid socket"); 281 | 282 | ready = true; 283 | } 284 | 285 | void startAccept(const std::string& address) 286 | { 287 | ready = false; 288 | 289 | std::pair addr = getAddress(address); 290 | 291 | startAccept(addr.first, addr.second); 292 | } 293 | 294 | void startAccept(uint32_t address, uint16_t port) 295 | { 296 | ready = false; 297 | 298 | if (socketFd != NULL_SOCKET) 299 | close(); 300 | 301 | createSocketFd(); 302 | 303 | localAddress = address; 304 | localPort = port; 305 | int value = 1; 306 | 307 | if (setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&value), sizeof(value)) < 0) 308 | throw std::system_error(getLastError(), std::system_category(), "setsockopt(SO_REUSEADDR) failed"); 309 | 310 | sockaddr_in serverAddress; 311 | memset(&serverAddress, 0, sizeof(serverAddress)); 312 | serverAddress.sin_family = AF_INET; 313 | serverAddress.sin_port = htons(localPort); 314 | serverAddress.sin_addr.s_addr = address; 315 | 316 | if (bind(socketFd, reinterpret_cast(&serverAddress), sizeof(serverAddress)) < 0) 317 | throw std::system_error(getLastError(), std::system_category(), "Failed to bind server socket to port " + std::to_string(localPort)); 318 | 319 | if (listen(socketFd, WAITING_QUEUE_SIZE) < 0) 320 | throw std::system_error(getLastError(), std::system_category(), "Failed to listen on " + ipToString(localAddress) + ":" + std::to_string(localPort)); 321 | 322 | accepting = true; 323 | ready = true; 324 | } 325 | 326 | void connect(const std::string& address) 327 | { 328 | ready = false; 329 | connecting = false; 330 | 331 | std::pair addr = getAddress(address); 332 | 333 | connect(addr.first, addr.second); 334 | } 335 | 336 | void connect(uint32_t address, uint16_t newPort) 337 | { 338 | ready = false; 339 | connecting = false; 340 | 341 | if (socketFd != NULL_SOCKET) 342 | close(); 343 | 344 | createSocketFd(); 345 | 346 | remoteAddress = address; 347 | remotePort = newPort; 348 | 349 | remoteAddressString = ipToString(remoteAddress) + ":" + std::to_string(remotePort); 350 | 351 | sockaddr_in addr; 352 | memset(&addr, 0, sizeof(addr)); 353 | addr.sin_family = AF_INET; 354 | addr.sin_addr.s_addr = remoteAddress; 355 | addr.sin_port = htons(remotePort); 356 | 357 | if (::connect(socketFd, reinterpret_cast(&addr), sizeof(addr)) < 0) 358 | { 359 | int error = getLastError(); 360 | 361 | #ifdef _WIN32 362 | if (error != WSAEWOULDBLOCK && 363 | error != WSAEINPROGRESS) 364 | #else 365 | if (error != EAGAIN && 366 | error != EWOULDBLOCK && 367 | error != EINPROGRESS) 368 | #endif 369 | { 370 | if (connectErrorCallback) 371 | connectErrorCallback(*this); 372 | 373 | throw std::system_error(error, std::system_category(), "Failed to connect to " + remoteAddressString); 374 | } 375 | 376 | connecting = true; 377 | } 378 | else 379 | { 380 | // connected 381 | ready = true; 382 | if (connectCallback) 383 | connectCallback(*this); 384 | } 385 | 386 | sockaddr_in localAddr; 387 | socklen_t localAddrSize = sizeof(localAddr); 388 | 389 | if (getsockname(socketFd, reinterpret_cast(&localAddr), &localAddrSize) != 0) 390 | { 391 | int error = getLastError(); 392 | closeSocketFd(); 393 | connecting = false; 394 | if (connectErrorCallback) 395 | connectErrorCallback(*this); 396 | throw std::system_error(error, std::system_category(), "Failed to get address of the socket connecting to " + remoteAddressString); 397 | } 398 | 399 | localAddress = localAddr.sin_addr.s_addr; 400 | localPort = ntohs(localAddr.sin_port); 401 | } 402 | 403 | bool isConnecting() const { return connecting; } 404 | 405 | float getConnectTimeout() const { return connectTimeout; } 406 | void setConnectTimeout(float timeout) { connectTimeout = timeout; } 407 | 408 | void setReadCallback(const std::function&)>& newReadCallback) 409 | { 410 | readCallback = newReadCallback; 411 | } 412 | 413 | void setCloseCallback(const std::function& newCloseCallback) 414 | { 415 | closeCallback = newCloseCallback; 416 | } 417 | 418 | void setAcceptCallback(const std::function& newAcceptCallback) 419 | { 420 | acceptCallback = newAcceptCallback; 421 | } 422 | 423 | void setConnectCallback(const std::function& newConnectCallback) 424 | { 425 | connectCallback = newConnectCallback; 426 | } 427 | 428 | void setConnectErrorCallback(const std::function& newConnectErrorCallback) 429 | { 430 | connectErrorCallback = newConnectErrorCallback; 431 | } 432 | 433 | void send(std::vector buffer) 434 | { 435 | if (socketFd == NULL_SOCKET) 436 | throw std::runtime_error("Invalid socket"); 437 | 438 | outData.insert(outData.end(), buffer.begin(), buffer.end()); 439 | } 440 | 441 | uint32_t getLocalAddress() const { return localAddress; } 442 | uint16_t getLocalPort() const { return localPort; } 443 | 444 | uint32_t getRemoteAddress() const { return remoteAddress; } 445 | uint16_t getRemotePort() const { return remotePort; } 446 | 447 | bool isBlocking() const { return blocking; } 448 | void setBlocking(bool newBlocking) 449 | { 450 | blocking = newBlocking; 451 | 452 | if (socketFd != NULL_SOCKET) 453 | setFdBlocking(newBlocking); 454 | } 455 | 456 | bool isReady() const { return ready; } 457 | bool hasOutData() const { return !outData.empty(); } 458 | 459 | private: 460 | Socket(Network& aNetwork, socket_t aSocketFd, bool aReady, 461 | uint32_t aLocalAddress, uint16_t aLocalPort, 462 | uint32_t aRemoteAddress, uint16_t aRemotePort); 463 | 464 | void read() 465 | { 466 | if (accepting) 467 | { 468 | sockaddr_in address; 469 | #ifdef _WIN32 470 | int addressLength = static_cast(sizeof(address)); 471 | #else 472 | socklen_t addressLength = sizeof(address); 473 | #endif 474 | 475 | socket_t clientFd = ::accept(socketFd, reinterpret_cast(&address), &addressLength); 476 | 477 | if (clientFd == NULL_SOCKET) 478 | { 479 | int error = getLastError(); 480 | 481 | #ifdef _WIN32 482 | if (error != WSAEWOULDBLOCK && 483 | error != WSAEINPROGRESS) 484 | #else 485 | if (error != EAGAIN && 486 | error != EWOULDBLOCK && 487 | error != EINPROGRESS) 488 | #endif 489 | throw std::system_error(error, std::system_category(), "Failed to accept client"); 490 | } 491 | else 492 | { 493 | Socket socket(network, clientFd, true, 494 | localAddress, localPort, 495 | address.sin_addr.s_addr, 496 | ntohs(address.sin_port)); 497 | 498 | if (acceptCallback) 499 | acceptCallback(*this, socket); 500 | } 501 | } 502 | else 503 | { 504 | return readData(); 505 | } 506 | } 507 | 508 | void write() 509 | { 510 | if (connecting) 511 | { 512 | connecting = false; 513 | ready = true; 514 | if (connectCallback) 515 | connectCallback(*this); 516 | } 517 | 518 | return writeData(); 519 | } 520 | 521 | void readData() 522 | { 523 | #if defined(__APPLE__) 524 | int flags = 0; 525 | #elif defined(_WIN32) 526 | int flags = 0; 527 | #else 528 | int flags = MSG_NOSIGNAL; 529 | #endif 530 | 531 | #ifdef _WIN32 532 | int size = recv(socketFd, reinterpret_cast(tempBuffer), sizeof(tempBuffer), flags); 533 | #else 534 | ssize_t size = recv(socketFd, reinterpret_cast(tempBuffer), sizeof(tempBuffer), flags); 535 | #endif 536 | 537 | if (size > 0) 538 | { 539 | inData.assign(tempBuffer, tempBuffer + size); 540 | 541 | if (readCallback) 542 | readCallback(*this, inData); 543 | } 544 | else if (size < 0) 545 | { 546 | int error = getLastError(); 547 | 548 | #ifdef _WIN32 549 | if (error != WSAEWOULDBLOCK && 550 | error != WSAEINPROGRESS) 551 | #else 552 | if (error != EAGAIN && 553 | error != EWOULDBLOCK && 554 | error != EINPROGRESS) 555 | #endif 556 | { 557 | disconnected(); 558 | 559 | if (error == ECONNRESET) 560 | throw std::system_error(error, std::system_category(), "Connection to " + remoteAddressString + " reset by peer"); 561 | else if (error == ECONNREFUSED) 562 | throw std::system_error(error, std::system_category(), "Connection to " + remoteAddressString + " refused"); 563 | else 564 | throw std::system_error(error, std::system_category(), "Failed to read from " + remoteAddressString); 565 | } 566 | } 567 | else // size == 0 568 | disconnected(); 569 | 570 | } 571 | 572 | void writeData() 573 | { 574 | if (ready && !outData.empty()) 575 | { 576 | #if defined(__APPLE__) 577 | int flags = 0; 578 | #elif defined(_WIN32) 579 | int flags = 0; 580 | #else 581 | int flags = MSG_NOSIGNAL; 582 | #endif 583 | 584 | #ifdef _WIN32 585 | int dataSize = static_cast(outData.size()); 586 | int size = ::send(socketFd, reinterpret_cast(outData.data()), dataSize, flags); 587 | #else 588 | size_t dataSize = static_cast(outData.size()); 589 | ssize_t size = ::send(socketFd, reinterpret_cast(outData.data()), dataSize, flags); 590 | #endif 591 | 592 | if (size < 0) 593 | { 594 | int error = getLastError(); 595 | #ifdef _WIN32 596 | if (error != WSAEWOULDBLOCK && 597 | error != WSAEINPROGRESS) 598 | #else 599 | if (error != EAGAIN && 600 | error != EWOULDBLOCK && 601 | error != EINPROGRESS) 602 | #endif 603 | { 604 | disconnected(); 605 | 606 | if (error == EPIPE) 607 | throw std::system_error(error, std::system_category(), "Failed to send data to " + remoteAddressString + ", socket has been shut down"); 608 | else if (error == ECONNRESET) 609 | throw std::system_error(error, std::system_category(), "Connection to " + remoteAddressString + " reset by peer"); 610 | else 611 | throw std::system_error(error, std::system_category(), "Failed to write to socket " + remoteAddressString); 612 | } 613 | } 614 | 615 | if (size > 0) 616 | outData.erase(outData.begin(), outData.begin() + size); 617 | } 618 | } 619 | 620 | void disconnected() 621 | { 622 | if (connecting) 623 | { 624 | connecting = false; 625 | ready = false; 626 | 627 | if (socketFd != NULL_SOCKET) 628 | closeSocketFd(); 629 | 630 | if (connectErrorCallback) 631 | connectErrorCallback(*this); 632 | } 633 | else 634 | { 635 | if (ready) 636 | { 637 | ready = false; 638 | 639 | if (closeCallback) 640 | closeCallback(*this); 641 | 642 | if (socketFd != NULL_SOCKET) 643 | closeSocketFd(); 644 | 645 | localAddress = 0; 646 | localPort = 0; 647 | remoteAddress = 0; 648 | remotePort = 0; 649 | ready = false; 650 | outData.clear(); 651 | } 652 | } 653 | } 654 | 655 | void createSocketFd() 656 | { 657 | socketFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 658 | 659 | if (socketFd == NULL_SOCKET) 660 | throw std::system_error(getLastError(), std::system_category(), "Failed to create socket"); 661 | 662 | if (!blocking) 663 | setFdBlocking(false); 664 | 665 | #ifdef __APPLE__ 666 | int set = 1; 667 | if (setsockopt(socketFd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(int)) != 0) 668 | throw std::system_error(errno, std::system_category(), "Failed to set socket option"); 669 | #endif 670 | } 671 | 672 | void closeSocketFd() 673 | { 674 | if (socketFd != NULL_SOCKET) 675 | { 676 | #ifdef _WIN32 677 | closesocket(socketFd); 678 | #else 679 | ::close(socketFd); 680 | #endif 681 | socketFd = NULL_SOCKET; 682 | } 683 | } 684 | 685 | void setFdBlocking(bool block) 686 | { 687 | if (socketFd == NULL_SOCKET) 688 | throw std::runtime_error("Invalid socket"); 689 | 690 | #ifdef _WIN32 691 | unsigned long mode = block ? 0 : 1; 692 | if (ioctlsocket(socketFd, FIONBIO, &mode) != 0) 693 | throw std::system_error(WSAGetLastError(), std::system_category(), "Failed to set socket mode"); 694 | #else 695 | int flags = fcntl(socketFd, F_GETFL, 0); 696 | if (flags < 0) 697 | throw std::system_error(errno, std::system_category(), "Failed to get socket flags"); 698 | flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); 699 | 700 | if (fcntl(socketFd, F_SETFL, flags) != 0) 701 | throw std::system_error(errno, std::system_category(), "Failed to set socket flags"); 702 | #endif 703 | } 704 | 705 | Network& network; 706 | 707 | socket_t socketFd = NULL_SOCKET; 708 | 709 | bool ready = false; 710 | bool blocking = true; 711 | 712 | uint32_t localAddress = 0; 713 | uint16_t localPort = 0; 714 | 715 | uint32_t remoteAddress = 0; 716 | uint16_t remotePort = 0; 717 | 718 | float connectTimeout = 10.0f; 719 | float timeSinceConnect = 0.0f; 720 | bool accepting = false; 721 | bool connecting = false; 722 | 723 | std::function&)> readCallback; 724 | std::function closeCallback; 725 | std::function acceptCallback; 726 | std::function connectCallback; 727 | std::function connectErrorCallback; 728 | 729 | std::vector inData; 730 | std::vector outData; 731 | 732 | std::string remoteAddressString; 733 | 734 | uint8_t tempBuffer[1024]; 735 | }; 736 | 737 | class Network final 738 | { 739 | friend Socket; 740 | public: 741 | Network() 742 | { 743 | previousTime = std::chrono::steady_clock::now(); 744 | } 745 | 746 | void update() 747 | { 748 | for (Socket* socket : socketDeleteSet) 749 | { 750 | auto i = std::find(sockets.begin(), sockets.end(), socket); 751 | 752 | if (i != sockets.end()) 753 | sockets.erase(i); 754 | } 755 | 756 | socketDeleteSet.clear(); 757 | 758 | for (Socket* socket : socketAddSet) 759 | { 760 | auto i = std::find(sockets.begin(), sockets.end(), socket); 761 | 762 | if (i == sockets.end()) 763 | sockets.push_back(socket); 764 | } 765 | 766 | socketAddSet.clear(); 767 | 768 | auto currentTime = std::chrono::steady_clock::now(); 769 | auto diff = std::chrono::duration_cast(currentTime - previousTime); 770 | 771 | float delta = diff.count() / 1000000000.0f; 772 | previousTime = currentTime; 773 | 774 | std::vector pollFds; 775 | pollFds.reserve(sockets.size()); 776 | 777 | for (auto socket : sockets) 778 | { 779 | if (socket->socketFd != NULL_SOCKET) 780 | { 781 | pollfd pollFd; 782 | pollFd.fd = socket->socketFd; 783 | pollFd.events = POLLIN | POLLOUT; 784 | 785 | pollFds.push_back(pollFd); 786 | } 787 | } 788 | 789 | if (!pollFds.empty()) 790 | { 791 | #ifdef _WIN32 792 | if (WSAPoll(pollFds.data(), static_cast(pollFds.size()), 0) < 0) 793 | throw std::system_error(WSAGetLastError(), std::system_category(), "Poll failed"); 794 | #else 795 | if (poll(pollFds.data(), static_cast(pollFds.size()), 0) < 0) 796 | throw std::system_error(errno, std::system_category(), "Poll failed"); 797 | #endif 798 | 799 | 800 | for (pollfd& pollFd : pollFds) 801 | { 802 | for (Socket* deleteSocket : socketDeleteSet) 803 | { 804 | auto i = std::find(sockets.begin(), sockets.end(), deleteSocket); 805 | 806 | if (i != sockets.end()) 807 | sockets.erase(i); 808 | } 809 | 810 | socketDeleteSet.clear(); 811 | 812 | auto i = std::find_if(sockets.begin(), sockets.end(), [&pollFd](Socket* socket) { 813 | return socket->socketFd == pollFd.fd; 814 | }); 815 | 816 | if (i != sockets.end()) 817 | { 818 | Socket* socket = *i; 819 | 820 | if (pollFd.revents & POLLIN) 821 | socket->read(); 822 | 823 | if (pollFd.revents & POLLOUT) 824 | socket->write(); 825 | 826 | socket->update(delta); 827 | } 828 | } 829 | } 830 | } 831 | 832 | private: 833 | void addSocket(Socket& socket) 834 | { 835 | socketAddSet.insert(&socket); 836 | 837 | auto setIterator = socketDeleteSet.find(&socket); 838 | 839 | if (setIterator != socketDeleteSet.end()) 840 | socketDeleteSet.erase(setIterator); 841 | } 842 | 843 | void removeSocket(Socket& socket) 844 | { 845 | socketDeleteSet.insert(&socket); 846 | 847 | auto setIterator = socketAddSet.find(&socket); 848 | 849 | if (setIterator != socketAddSet.end()) 850 | socketAddSet.erase(setIterator); 851 | } 852 | 853 | #ifdef _WIN32 854 | WinSock winSock; 855 | #endif 856 | 857 | std::vector sockets; 858 | std::set socketAddSet; 859 | std::set socketDeleteSet; 860 | 861 | std::chrono::steady_clock::time_point previousTime; 862 | }; 863 | 864 | Socket::Socket(Network& aNetwork): 865 | network(aNetwork) 866 | { 867 | network.addSocket(*this); 868 | } 869 | 870 | Socket::~Socket() 871 | { 872 | network.removeSocket(*this); 873 | 874 | try 875 | { 876 | writeData(); 877 | } 878 | catch (...) 879 | { 880 | } 881 | 882 | closeSocketFd(); 883 | } 884 | 885 | Socket::Socket(Socket&& other): 886 | network(other.network), 887 | socketFd(other.socketFd), 888 | ready(other.ready), 889 | blocking(other.blocking), 890 | localAddress(other.localAddress), 891 | localPort(other.localPort), 892 | remoteAddress(other.remoteAddress), 893 | remotePort(other.remotePort), 894 | connectTimeout(other.connectTimeout), 895 | timeSinceConnect(other.timeSinceConnect), 896 | accepting(other.accepting), 897 | connecting(other.connecting), 898 | readCallback(std::move(other.readCallback)), 899 | closeCallback(std::move(other.closeCallback)), 900 | acceptCallback(std::move(other.acceptCallback)), 901 | connectCallback(std::move(other.connectCallback)), 902 | connectErrorCallback(std::move(other.connectErrorCallback)), 903 | outData(std::move(other.outData)) 904 | { 905 | network.addSocket(*this); 906 | 907 | remoteAddressString = ipToString(remoteAddress) + ":" + std::to_string(remotePort); 908 | 909 | other.socketFd = NULL_SOCKET; 910 | other.ready = false; 911 | other.blocking = true; 912 | other.localAddress = 0; 913 | other.localPort = 0; 914 | other.remoteAddress = 0; 915 | other.remotePort = 0; 916 | other.connecting = false; 917 | other.connectTimeout = 10.0f; 918 | other.timeSinceConnect = 0.0f; 919 | } 920 | 921 | Socket::Socket(Network& aNetwork, socket_t aSocketFd, bool aReady, 922 | uint32_t aLocalAddress, uint16_t aLocalPort, 923 | uint32_t aRemoteAddress, uint16_t aRemotePort): 924 | network(aNetwork), socketFd(aSocketFd), ready(aReady), 925 | localAddress(aLocalAddress), localPort(aLocalPort), 926 | remoteAddress(aRemoteAddress), remotePort(aRemotePort) 927 | { 928 | remoteAddressString = ipToString(remoteAddress) + ":" + std::to_string(remotePort); 929 | network.addSocket(*this); 930 | } 931 | } 932 | #endif // CPPSOCKET_HPP 933 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | debug=0 2 | ifeq ($(OS),Windows_NT) 3 | platform=windows 4 | else 5 | architecture=$(shell uname -m) 6 | 7 | ifeq ($(shell uname -s),Linux) 8 | platform=linux 9 | endif 10 | ifeq ($(shell uname -s),Darwin) 11 | platform=macos 12 | endif 13 | ifeq ($(shell uname -s),Haiku) 14 | platform=haiku 15 | endif 16 | endif 17 | 18 | CXXFLAGS=-c -std=c++11 -Wall -O2 -I../include 19 | LDFLAGS=-O2 20 | ifeq ($(platform),haiku) 21 | LDFLAGS+=-lnetwork 22 | endif 23 | SOURCES=main.cpp 24 | BASE_NAMES=$(basename $(SOURCES)) 25 | OBJECTS=$(BASE_NAMES:=.o) 26 | EXECUTABLE=test 27 | 28 | all: $(EXECUTABLE) 29 | ifeq ($(debug),1) 30 | all: CXXFLAGS+=-DDEBUG -g 31 | endif 32 | 33 | $(EXECUTABLE): $(OBJECTS) 34 | $(CXX) $(OBJECTS) $(LDFLAGS) -o $@ 35 | 36 | %.o: %.cpp 37 | $(CXX) $(CXXFLAGS) $< -o $@ 38 | 39 | .PHONY: clean 40 | clean: 41 | ifeq ($(platform),windows) 42 | -del /f /q "$(EXECUTABLE).exe" "*.o" 43 | else 44 | $(RM) $(EXECUTABLE) *.o $(EXECUTABLE).exe 45 | endif -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // cppsocket 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "Socket.hpp" 10 | 11 | static void printUsage(const std::string& executable) 12 | { 13 | std::cout << "Usage: " << executable << " [server|client] [port|address]" << std::endl; 14 | } 15 | 16 | int main(int argc, const char* argv[]) 17 | { 18 | try 19 | { 20 | if (argc < 3) 21 | { 22 | printUsage(argc ? argv[0] : "test"); 23 | return EXIT_SUCCESS; 24 | } 25 | 26 | std::string type = argv[1]; 27 | std::string address = argv[2]; 28 | 29 | cppsocket::Network network; 30 | cppsocket::Socket server(network); 31 | cppsocket::Socket client(network); 32 | std::vector clientSockets; 33 | 34 | if (type == "server") 35 | { 36 | std::istringstream buffer(address); 37 | uint16_t port; 38 | buffer >> port; 39 | 40 | server.setBlocking(false); 41 | server.startAccept(cppsocket::ANY_ADDRESS, port); 42 | 43 | server.setAcceptCallback([&clientSockets](cppsocket::Socket&, cppsocket::Socket& c) { 44 | std::cout << "Client connected" << std::endl; 45 | c.startRead(); 46 | c.send({'t', 'e', 's', 't', '\0'}); 47 | c.setCloseCallback([&clientSockets](cppsocket::Socket& socket) { 48 | std::cout << "Client at " << cppsocket::ipToString(socket.getRemoteAddress()) << " disconnected" << std::endl; 49 | 50 | for (auto i = clientSockets.begin(); i != clientSockets.end();) 51 | { 52 | if (&(*i) == &socket) 53 | { 54 | clientSockets.erase(i); 55 | break; 56 | } 57 | else 58 | ++i; 59 | } 60 | 61 | }); 62 | clientSockets.push_back(std::move(c)); 63 | }); 64 | } 65 | else if (type == "client") 66 | { 67 | client.setBlocking(false); 68 | client.setConnectTimeout(2.0f); 69 | client.connect(address); 70 | 71 | client.setReadCallback([](cppsocket::Socket& socket, const std::vector& data) { 72 | std::cout << "Got data: " << data.data() << " from " << cppsocket::ipToString(socket.getRemoteAddress()) << std::endl; 73 | }); 74 | 75 | client.setConnectCallback([](cppsocket::Socket& socket) { 76 | std::cout << "Connected to " << cppsocket::ipToString(socket.getRemoteAddress()) << std::endl; 77 | 78 | socket.send({'t', 'e', 's', 't', '\0'}); 79 | }); 80 | 81 | client.setConnectErrorCallback([&client, address](cppsocket::Socket& socket) { 82 | std::cout << "Failed to connected to " << cppsocket::ipToString(socket.getRemoteAddress()) << std::endl; 83 | 84 | client.connect(address); 85 | }); 86 | } 87 | 88 | const std::chrono::microseconds sleepTime(10000); 89 | 90 | for (;;) 91 | { 92 | network.update(); 93 | 94 | std::this_thread::sleep_for(sleepTime); 95 | } 96 | } 97 | catch (const std::exception& e) 98 | { 99 | std::cerr << "Error: " << e.what() << std::endl; 100 | return EXIT_FAILURE; 101 | } 102 | catch (...) 103 | { 104 | std::cerr << "Error" << std::endl; 105 | return EXIT_FAILURE; 106 | } 107 | 108 | return EXIT_SUCCESS; 109 | } 110 | -------------------------------------------------------------------------------- /test/test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{614C7EC0-3262-40DF-B884-224B959A01F9}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {614C7EC0-3262-40DF-B884-224B959A01F9}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {614C7EC0-3262-40DF-B884-224B959A01F9}.Debug|Win32.Build.0 = Debug|Win32 18 | {614C7EC0-3262-40DF-B884-224B959A01F9}.Debug|x64.ActiveCfg = Debug|x64 19 | {614C7EC0-3262-40DF-B884-224B959A01F9}.Debug|x64.Build.0 = Debug|x64 20 | {614C7EC0-3262-40DF-B884-224B959A01F9}.Release|Win32.ActiveCfg = Release|Win32 21 | {614C7EC0-3262-40DF-B884-224B959A01F9}.Release|Win32.Build.0 = Release|Win32 22 | {614C7EC0-3262-40DF-B884-224B959A01F9}.Release|x64.ActiveCfg = Release|x64 23 | {614C7EC0-3262-40DF-B884-224B959A01F9}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /test/test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {614C7EC0-3262-40DF-B884-224B959A01F9} 29 | Win32Proj 30 | rtmp_relay 31 | 8.1 32 | 33 | 34 | 35 | Application 36 | true 37 | v120 38 | Unicode 39 | 40 | 41 | Application 42 | false 43 | v120 44 | true 45 | Unicode 46 | 47 | 48 | Application 49 | true 50 | v120 51 | Unicode 52 | 53 | 54 | Application 55 | false 56 | v120 57 | true 58 | Unicode 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | true 80 | ..\include;$(IncludePath) 81 | 82 | 83 | true 84 | ..\include;$(IncludePath) 85 | 86 | 87 | false 88 | ..\include;$(IncludePath) 89 | 90 | 91 | false 92 | ..\include;$(IncludePath) 93 | 94 | 95 | 96 | Level3 97 | Disabled 98 | _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 99 | true 100 | 101 | 102 | Console 103 | true 104 | ws2_32.lib;%(AdditionalDependencies) 105 | 106 | 107 | 108 | 109 | Level3 110 | Disabled 111 | _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 112 | true 113 | 114 | 115 | Console 116 | true 117 | ws2_32.lib;%(AdditionalDependencies) 118 | 119 | 120 | 121 | 122 | Level3 123 | MaxSpeed 124 | true 125 | true 126 | _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 127 | true 128 | 129 | 130 | Console 131 | true 132 | true 133 | true 134 | ws2_32.lib;%(AdditionalDependencies) 135 | 136 | 137 | 138 | 139 | Level3 140 | MaxSpeed 141 | true 142 | true 143 | _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 144 | true 145 | 146 | 147 | Console 148 | true 149 | true 150 | true 151 | ws2_32.lib;%(AdditionalDependencies) 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /test/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4a38d4eb-f6e2-47ed-90c1-202b4f412c8b} 6 | 7 | 8 | {4fc5987b-5821-4436-81e9-10aa7da94d5c} 9 | 10 | 11 | 12 | 13 | test 14 | 15 | 16 | 17 | 18 | cppsocket 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/test.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 30513E531D390DE600F9B4BA /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 30513E521D390DE600F9B4BA /* main.cpp */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 300934071C873DF200CC50D3 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 300934091C873DF200CC50D3 /* test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 30513E521D390DE600F9B4BA /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; 28 | 3085DA1C2119063B00F4C2D0 /* Socket.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Socket.hpp; path = include/Socket.hpp; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 300934061C873DF200CC50D3 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 300934001C873DF200CC50D3 = { 43 | isa = PBXGroup; 44 | children = ( 45 | 30513E371D390D8200F9B4BA /* cppsocket */, 46 | 30513E281D37C61100F9B4BA /* test */, 47 | 3009340A1C873DF200CC50D3 /* Products */, 48 | ); 49 | sourceTree = ""; 50 | }; 51 | 3009340A1C873DF200CC50D3 /* Products */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | 300934091C873DF200CC50D3 /* test */, 55 | ); 56 | name = Products; 57 | sourceTree = ""; 58 | }; 59 | 30513E281D37C61100F9B4BA /* test */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 30513E521D390DE600F9B4BA /* main.cpp */, 63 | ); 64 | name = test; 65 | sourceTree = ""; 66 | }; 67 | 30513E371D390D8200F9B4BA /* cppsocket */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 3085DA1C2119063B00F4C2D0 /* Socket.hpp */, 71 | ); 72 | name = cppsocket; 73 | path = ..; 74 | sourceTree = ""; 75 | }; 76 | /* End PBXGroup section */ 77 | 78 | /* Begin PBXNativeTarget section */ 79 | 300934081C873DF200CC50D3 /* test */ = { 80 | isa = PBXNativeTarget; 81 | buildConfigurationList = 300934101C873DF200CC50D3 /* Build configuration list for PBXNativeTarget "test" */; 82 | buildPhases = ( 83 | 300934051C873DF200CC50D3 /* Sources */, 84 | 300934061C873DF200CC50D3 /* Frameworks */, 85 | 300934071C873DF200CC50D3 /* CopyFiles */, 86 | ); 87 | buildRules = ( 88 | ); 89 | dependencies = ( 90 | ); 91 | name = test; 92 | productName = rtmp_relay; 93 | productReference = 300934091C873DF200CC50D3 /* test */; 94 | productType = "com.apple.product-type.tool"; 95 | }; 96 | /* End PBXNativeTarget section */ 97 | 98 | /* Begin PBXProject section */ 99 | 300934011C873DF200CC50D3 /* Project object */ = { 100 | isa = PBXProject; 101 | attributes = { 102 | LastUpgradeCheck = 0800; 103 | ORGANIZATIONNAME = "Bool Games"; 104 | TargetAttributes = { 105 | 300934081C873DF200CC50D3 = { 106 | CreatedOnToolsVersion = 7.2.1; 107 | }; 108 | }; 109 | }; 110 | buildConfigurationList = 300934041C873DF200CC50D3 /* Build configuration list for PBXProject "test" */; 111 | compatibilityVersion = "Xcode 3.2"; 112 | developmentRegion = English; 113 | hasScannedForEncodings = 0; 114 | knownRegions = ( 115 | en, 116 | ); 117 | mainGroup = 300934001C873DF200CC50D3; 118 | productRefGroup = 3009340A1C873DF200CC50D3 /* Products */; 119 | projectDirPath = ""; 120 | projectRoot = ""; 121 | targets = ( 122 | 300934081C873DF200CC50D3 /* test */, 123 | ); 124 | }; 125 | /* End PBXProject section */ 126 | 127 | /* Begin PBXSourcesBuildPhase section */ 128 | 300934051C873DF200CC50D3 /* Sources */ = { 129 | isa = PBXSourcesBuildPhase; 130 | buildActionMask = 2147483647; 131 | files = ( 132 | 30513E531D390DE600F9B4BA /* main.cpp in Sources */, 133 | ); 134 | runOnlyForDeploymentPostprocessing = 0; 135 | }; 136 | /* End PBXSourcesBuildPhase section */ 137 | 138 | /* Begin XCBuildConfiguration section */ 139 | 3009340E1C873DF200CC50D3 /* Debug */ = { 140 | isa = XCBuildConfiguration; 141 | buildSettings = { 142 | ALWAYS_SEARCH_USER_PATHS = NO; 143 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 144 | CLANG_CXX_LIBRARY = "libc++"; 145 | CLANG_ENABLE_MODULES = YES; 146 | CLANG_ENABLE_OBJC_ARC = YES; 147 | CLANG_WARN_ASSIGN_ENUM = YES; 148 | CLANG_WARN_BOOL_CONVERSION = YES; 149 | CLANG_WARN_CONSTANT_CONVERSION = YES; 150 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 151 | CLANG_WARN_EMPTY_BODY = YES; 152 | CLANG_WARN_ENUM_CONVERSION = YES; 153 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 154 | CLANG_WARN_INFINITE_RECURSION = YES; 155 | CLANG_WARN_INT_CONVERSION = YES; 156 | CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES; 157 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 158 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 159 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 160 | CLANG_WARN_UNREACHABLE_CODE = YES; 161 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 162 | CODE_SIGN_IDENTITY = "-"; 163 | COPY_PHASE_STRIP = NO; 164 | DEBUG_INFORMATION_FORMAT = dwarf; 165 | ENABLE_STRICT_OBJC_MSGSEND = YES; 166 | ENABLE_TESTABILITY = YES; 167 | GCC_C_LANGUAGE_STANDARD = gnu99; 168 | GCC_DYNAMIC_NO_PIC = NO; 169 | GCC_NO_COMMON_BLOCKS = YES; 170 | GCC_OPTIMIZATION_LEVEL = 0; 171 | GCC_PREPROCESSOR_DEFINITIONS = ( 172 | "DEBUG=1", 173 | "$(inherited)", 174 | ); 175 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; 176 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; 177 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 178 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 179 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 180 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 181 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 182 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 183 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 184 | GCC_WARN_SHADOW = YES; 185 | GCC_WARN_SIGN_COMPARE = YES; 186 | GCC_WARN_UNDECLARED_SELECTOR = YES; 187 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 188 | GCC_WARN_UNKNOWN_PRAGMAS = YES; 189 | GCC_WARN_UNUSED_FUNCTION = YES; 190 | GCC_WARN_UNUSED_LABEL = YES; 191 | GCC_WARN_UNUSED_PARAMETER = YES; 192 | GCC_WARN_UNUSED_VARIABLE = YES; 193 | MACOSX_DEPLOYMENT_TARGET = 10.11; 194 | MTL_ENABLE_DEBUG_INFO = YES; 195 | ONLY_ACTIVE_ARCH = YES; 196 | SDKROOT = macosx; 197 | }; 198 | name = Debug; 199 | }; 200 | 3009340F1C873DF200CC50D3 /* Release */ = { 201 | isa = XCBuildConfiguration; 202 | buildSettings = { 203 | ALWAYS_SEARCH_USER_PATHS = NO; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_WARN_ASSIGN_ENUM = YES; 209 | CLANG_WARN_BOOL_CONVERSION = YES; 210 | CLANG_WARN_CONSTANT_CONVERSION = YES; 211 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 212 | CLANG_WARN_EMPTY_BODY = YES; 213 | CLANG_WARN_ENUM_CONVERSION = YES; 214 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 215 | CLANG_WARN_INFINITE_RECURSION = YES; 216 | CLANG_WARN_INT_CONVERSION = YES; 217 | CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES; 218 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 219 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 220 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 221 | CLANG_WARN_UNREACHABLE_CODE = YES; 222 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 223 | CODE_SIGN_IDENTITY = "-"; 224 | COPY_PHASE_STRIP = NO; 225 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 226 | ENABLE_NS_ASSERTIONS = NO; 227 | ENABLE_STRICT_OBJC_MSGSEND = YES; 228 | GCC_C_LANGUAGE_STANDARD = gnu99; 229 | GCC_NO_COMMON_BLOCKS = YES; 230 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; 231 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; 232 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 233 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 234 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 235 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 236 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 237 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 238 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 239 | GCC_WARN_SHADOW = YES; 240 | GCC_WARN_SIGN_COMPARE = YES; 241 | GCC_WARN_UNDECLARED_SELECTOR = YES; 242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 243 | GCC_WARN_UNKNOWN_PRAGMAS = YES; 244 | GCC_WARN_UNUSED_FUNCTION = YES; 245 | GCC_WARN_UNUSED_LABEL = YES; 246 | GCC_WARN_UNUSED_PARAMETER = YES; 247 | GCC_WARN_UNUSED_VARIABLE = YES; 248 | MACOSX_DEPLOYMENT_TARGET = 10.11; 249 | MTL_ENABLE_DEBUG_INFO = NO; 250 | SDKROOT = macosx; 251 | }; 252 | name = Release; 253 | }; 254 | 300934111C873DF200CC50D3 /* Debug */ = { 255 | isa = XCBuildConfiguration; 256 | buildSettings = { 257 | HEADER_SEARCH_PATHS = ../include; 258 | PRODUCT_NAME = "$(TARGET_NAME)"; 259 | WARNING_CFLAGS = "-Wold-style-cast"; 260 | }; 261 | name = Debug; 262 | }; 263 | 300934121C873DF200CC50D3 /* Release */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | HEADER_SEARCH_PATHS = ../include; 267 | PRODUCT_NAME = "$(TARGET_NAME)"; 268 | WARNING_CFLAGS = "-Wold-style-cast"; 269 | }; 270 | name = Release; 271 | }; 272 | /* End XCBuildConfiguration section */ 273 | 274 | /* Begin XCConfigurationList section */ 275 | 300934041C873DF200CC50D3 /* Build configuration list for PBXProject "test" */ = { 276 | isa = XCConfigurationList; 277 | buildConfigurations = ( 278 | 3009340E1C873DF200CC50D3 /* Debug */, 279 | 3009340F1C873DF200CC50D3 /* Release */, 280 | ); 281 | defaultConfigurationIsVisible = 0; 282 | defaultConfigurationName = Release; 283 | }; 284 | 300934101C873DF200CC50D3 /* Build configuration list for PBXNativeTarget "test" */ = { 285 | isa = XCConfigurationList; 286 | buildConfigurations = ( 287 | 300934111C873DF200CC50D3 /* Debug */, 288 | 300934121C873DF200CC50D3 /* Release */, 289 | ); 290 | defaultConfigurationIsVisible = 0; 291 | defaultConfigurationName = Release; 292 | }; 293 | /* End XCConfigurationList section */ 294 | }; 295 | rootObject = 300934011C873DF200CC50D3 /* Project object */; 296 | } 297 | -------------------------------------------------------------------------------- /test/test.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | --------------------------------------------------------------------------------