My Project
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros
communication.c
Go to the documentation of this file.
1 /*
2 START OF LICENSE STUB
3  DeDOS: Declarative Dispersion-Oriented Software
4  Copyright (C) 2017 University of Pennsylvania, Georgetown University
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 END OF LICENSE STUB
19 */
26 #include "communication.h"
27 #include "logging.h"
28 
29 #include <arpa/inet.h>
30 
35 #define MAX_READ_ATTEMPTS 100
36 
37 int read_payload(int fd, size_t size, void *buff) {
38  ssize_t rtn = 0;
39  int attempts = 0;
40  do {
41  log(LOG_READS, "Attempting to read payload of size %d", (int)size - (int)rtn);
42  int new_rtn = recv(fd, buff + rtn, size - rtn, 0);
43  if (new_rtn < 0 && errno != EAGAIN) {
44  log_perror("Error reading from fd: %d", fd);
45  return -1;
46  }
47  if (attempts++ > MAX_READ_ATTEMPTS) {
48  log_error("Attempted to read %d times", MAX_READ_ATTEMPTS);
49  return -1;
50  }
51  if (new_rtn > 0)
52  rtn += new_rtn;
53  } while ((errno == EAGAIN || rtn > 0) && (int)rtn < (int)size);
54  if (rtn == 0) {
55  log(LOG_CONNECTIONS, "fd %d has been closed by peer", fd);
56  return 1;
57  }
58  if (rtn != size) {
59  log_error("Could not read full runtime payload from socket %d. "
60  "Requested: %d, received: %d", fd, (int)size, (int)rtn);
61  return -1;
62  }
63  return 0;
64 }
65 
66 ssize_t send_to_endpoint(int fd, void *data, size_t data_len) {
67  ssize_t size = 0;
68  while (size < data_len) {
69  ssize_t rtn = write(fd, data + size, data_len - size);
70  if (rtn <= 0) {
71  log_error("Error sending buffer to endpoint with socket %d", fd);
72  break;
73  } else if (rtn < data_len) {
74  log_warn("Full buffer not sent to endpoint!");
75  }
76  size += rtn;
77  }
78  return size;
79 }
80 
81 int init_connected_socket(struct sockaddr_in *addr) {
82 
83  int sock = socket(AF_INET, SOCK_STREAM, 0);
84  if (sock < 0) {
85  log_perror("Failed to create socket");
86  return -1;
87  }
88 
89  // ???: Why set REUSEPORT and REUSEADDR on a socket that's not binding?
90  int val = 1;
91  if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
92  &val, sizeof(val)) < 0 ) {
93  log_perror("Error setting SO_REUSEPORT");
94  }
95  val = 1;
96  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
97  &val, sizeof(val)) < 0) {
98  log_perror("Error setting SO_REUSEADDR");
99  }
100  char ip[INET_ADDRSTRLEN];
101  inet_ntop(AF_INET, &addr->sin_addr, ip, INET_ADDRSTRLEN);
102  int port = ntohs(addr->sin_port);
103  log(LOG_CONNECTIONS, "Attepting to connect to socket at %s:%d", ip, port);
104  if (connect(sock, (struct sockaddr*)addr, sizeof(*addr)) < 0) {
105  log_perror("Failed to connect to socket at %s:%d", ip, port);
106  close(sock);
107  return -1;
108  }
109 
110  log(LOG_CONNECTIONS, "Connected socket to %s:%d", ip, port);
111  return sock;
112 }
113 
114 int init_bound_socket(int port) {
115  int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
116  if (sock == -1) {
117  log_perror("Failed to create socket");
118  return -1;
119  }
120  int val = 1;
121  if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) < 0) {
122  log_perror("Error setting SO_REUSEPORT on socket");
123  return -1;
124  }
125  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
126  log_perror("Error setting SO_REUSEADDR on socket");
127  return -1;
128  }
129 
130  struct sockaddr_in addr;
131  addr.sin_family = AF_INET;
132  addr.sin_port = htons(port);
133  addr.sin_addr.s_addr = htonl(INADDR_ANY);
134 
135  if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
136  log_perror("Failed to bind to port %d", port);
137  return -1;
138  }
139  return sock;
140 }
141 
145 #define BACKLOG 1024
146 
147 int init_listening_socket(int port) {
148  int sock = init_bound_socket(port);
149  if (sock < 0) {
150  log_error("Could not start listening socket due to failed bind");
151  return -1;
152  }
153 
154  int rtn = listen(sock, BACKLOG);
155  if (rtn < 0) {
156  log_perror("Error starting listening socket");
157  return -1;
158  }
159  log(LOG_COMMUNICATION, "Started listening socket on fd %d", sock);
160  return sock;
161 }
int init_connected_socket(struct sockaddr_in *addr)
Initializes a socket that is connected to a given address.
Definition: communication.c:81
Interface for general-purpose socket communication.
int read_payload(int fd, size_t size, void *buff)
Reads a buffer of a given size from a file descriptor.
Definition: communication.c:37
#define log_perror(fmt,...)
Definition: logging.h:102
Logging of status messages to the terminal.
#define log_error(fmt,...)
Definition: logging.h:101
#define MAX_READ_ATTEMPTS
The maximum number of times that a call to read() can be attempted for a single buffer before giving ...
Definition: communication.c:35
#define BACKLOG
The backlog size for listening sockets.
int init_listening_socket(int port)
Initializes a socket which is bound to and listening on the given port.
#define log(level, fmt,...)
Log at a custom level.
Definition: logging.h:147
ssize_t send_to_endpoint(int fd, void *data, size_t data_len)
Writes a buffer of a given size to a file descriptor.
Definition: communication.c:66
int init_bound_socket(int port)
Initializes a socket which is bound to a given port (and any local IP address).
#define log_warn(fmt,...)
Definition: logging.h:113