socket_listener.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Project headers
  2. #include "headers/socket_listener.h"
  3. #include "headers/constants.h"
  4. // System libraries
  5. #include <arpa/inet.h>
  6. #include <netdb.h>
  7. #include <string.h>
  8. #include <sys/socket.h>
  9. #include <sys/types.h>
  10. #include <unistd.h>
  11. // C++ Libraries
  12. #include <iostream>
  13. #include <string>
  14. /**
  15. * Constructor
  16. * Initialize with ip_address and port
  17. */
  18. SocketListener::SocketListener(std::string ip_address, int port)
  19. : m_ip_address(ip_address), m_port(port) {}
  20. /**
  21. * Destructor
  22. * TODO: Determine if we should make buffer a class member
  23. */
  24. SocketListener::~SocketListener() { cleanup(); }
  25. /**
  26. * sendMessage
  27. * @method
  28. * Send a null-terminated array of characters, supplied as a const char pointer,
  29. * to a client socket
  30. */
  31. void SocketListener::sendMessage(int clientSocket, std::string msg) {
  32. send(clientSocket, msg.c_str(), msg.size() + 1, 0);
  33. }
  34. /**
  35. * init
  36. * TODO: Initialize buffer memory, if buffer is to be a class member
  37. */
  38. bool SocketListener::init() {
  39. std::cout << "Initializing socket listener" << std::endl;
  40. return true;
  41. }
  42. /**
  43. * run
  44. * @method
  45. * Main message loop
  46. * TODO: Implement multithreading
  47. */
  48. void SocketListener::run() {
  49. // Declare, define and initialize a character buffer
  50. char buf[MAX_BUFFER_SIZE] = {};
  51. // Begin listening loop
  52. while (true) {
  53. // Call system to open a listening socket, and return its file descriptor
  54. int listening_socket_fd = createSocket();
  55. if (listening_socket_fd == SOCKET_ERROR) {
  56. std::cout << "Socket error: shutting down server" << std::endl;
  57. break;
  58. }
  59. // wait for a client connection and get its socket file descriptor
  60. int client_socket_fd = waitForConnection(listening_socket_fd);
  61. if (socket != SOCKET_ERROR) {
  62. // Destroy listening socket and deallocate its file descriptor. Only use
  63. // the client socket now.
  64. close(listening_socket_fd);
  65. std::string buffer_string{}; // Initialize a string buffer
  66. while (true) {
  67. memset(buf, 0, MAX_BUFFER_SIZE); // Zero the character buffer
  68. int bytes_received = 0;
  69. // Receive and write incoming data to buffer and return the number of
  70. // bytes received
  71. bytes_received =
  72. recv(client_socket_fd, buf,
  73. MAX_BUFFER_SIZE - 2, // Leave room for null-termination
  74. 0);
  75. buf[MAX_BUFFER_SIZE - 1] = 0; // Null-terminate the character buffer
  76. if (bytes_received > 0) {
  77. buffer_string += buf;
  78. std::cout << "Bytes received: " << bytes_received << "\nData: " << buf
  79. << std::endl;
  80. // Handle incoming message
  81. onMessageReceived(socket, std::string(buf));
  82. } else {
  83. std::cout << "client disconnected" << std::endl;
  84. break;
  85. }
  86. }
  87. // Zero the buffer again before closing
  88. memset(buf, 0, MAX_BUFFER_SIZE);
  89. // TODO: Determine if we should free memory, or handle as class member
  90. close(client_socket_fd); // Destroy client socket and deallocate its fd
  91. }
  92. }
  93. }
  94. /**
  95. * cleanUp
  96. * @method
  97. * TODO: Determine if we should be cleaning up buffer memory
  98. */
  99. void SocketListener::cleanup() { std::cout << "Cleaning up" << std::endl; }
  100. /**
  101. * createSocket
  102. * Open a listening socket and return its file descriptor
  103. */
  104. int SocketListener::createSocket() {
  105. /* Call the system to open a socket passing arguments for
  106. ipv4 family, tcp type and no additional protocol info */
  107. int listening_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  108. if (listening_socket_fd != SOCKET_ERROR) {
  109. // Create socket structure to hold address and type
  110. sockaddr_in socket_struct;
  111. socket_struct.sin_family = AF_INET; // ipv4
  112. socket_struct.sin_port =
  113. htons(m_port); // convert byte order of port value from host to network
  114. inet_pton(AF_INET, m_ip_address.c_str(), // convert address to binary
  115. &socket_struct.sin_addr);
  116. // Bind local socket address to socket file descriptor
  117. int bind_result = bind(
  118. listening_socket_fd, // TODO: Use C++ cast on next line?
  119. (sockaddr *)&socket_struct, // cast socket_struct to more generic type
  120. sizeof(socket_struct));
  121. if (bind_result != SOCKET_ERROR) {
  122. // Listen for connections to socket and allow up to max number of
  123. // connections for queue
  124. int listen_result = listen(listening_socket_fd, SOMAXCONN);
  125. if (listen_result == SOCKET_ERROR) {
  126. return WAIT_SOCKET_FAILURE;
  127. }
  128. } else {
  129. return WAIT_SOCKET_FAILURE;
  130. }
  131. }
  132. return listening_socket_fd; // Return socket file descriptor
  133. }
  134. /**
  135. * waitForConnection
  136. * @method
  137. * Takes first connection on queue of pending connections, creates a new socket
  138. * and returns its file descriptor
  139. */
  140. int SocketListener::waitForConnection(int listening_socket) {
  141. int client_socket_fd = accept(listening_socket, NULL, NULL);
  142. return client_socket_fd;
  143. }
  144. /**
  145. * onMessageReceived
  146. * @method
  147. * @override
  148. * Handle messages successfully received from a client socket
  149. */
  150. void SocketListener::onMessageReceived(int socket_id, std::string message) {
  151. sendMessage(socket_id, message);
  152. }