Line data Source code
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 : */
20 : #include "webserver/socketops.h"
21 : #include "webserver/webserver.h"
22 : #include <unistd.h>
23 : #include "logging.h"
24 : #include <netinet/ip.h>
25 :
26 :
27 : static struct sock_settings ws_sock_settings = {
28 : .domain = AF_INET,
29 : .type = SOCK_STREAM,
30 : .protocol = 0,
31 : .bind_ip = INADDR_ANY,
32 : .reuse_addr = 1,
33 : .reuse_port = 1
34 : };
35 :
36 0 : struct sock_settings *webserver_sock_settings(int port) {
37 0 : ws_sock_settings.port = port;
38 0 : return &ws_sock_settings;
39 : }
40 :
41 : #define SOCKET_BACKLOG 512
42 :
43 0 : int init_socket(struct sock_settings *settings) {
44 :
45 0 : int socket_fd = socket(
46 : settings->domain,
47 : settings->type,
48 : settings->protocol);
49 :
50 0 : if ( socket_fd == -1 ) {
51 0 : log_perror("socket() failed");
52 0 : return -1;
53 : }
54 :
55 0 : int opt = settings->reuse_addr;
56 0 : if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
57 0 : log_perror("setsockopt() failed for reuseaddr");
58 : }
59 0 : opt = settings->reuse_port;
60 0 : if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(&opt)) == -1) {
61 0 : log_perror("setsockopt() failed for reuseport");
62 : }
63 :
64 : struct sockaddr_in addr;
65 0 : addr.sin_family = settings->domain;
66 0 : addr.sin_addr.s_addr = settings->bind_ip;
67 0 : addr.sin_port = htons(settings->port);
68 :
69 0 : if (bind(socket_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
70 0 : log_perror("bind() failed");
71 0 : close(socket_fd);
72 0 : return -1;
73 : }
74 :
75 0 : if (listen(socket_fd, SOCKET_BACKLOG) == -1) {
76 0 : log_perror("listen() failed");
77 0 : close(socket_fd);
78 0 : return -1;
79 : }
80 :
81 0 : return socket_fd;
82 : }
83 :
84 0 : int read_socket(int fd, char *buf, int *buf_size) {
85 0 : int num_bytes = read(fd, buf, *buf_size);
86 0 : if (num_bytes >= 0) {
87 0 : *buf_size = num_bytes;
88 0 : return WS_COMPLETE;
89 : } else {
90 0 : if (errno == EAGAIN) {
91 0 : return WS_INCOMPLETE_READ;
92 : } else {
93 0 : log_perror("Error reading from socket %d", fd);
94 0 : return WS_ERROR;
95 : }
96 : }
97 : }
98 :
99 0 : int write_socket(int fd, char *buf, int *buf_size) {
100 0 : int num_bytes = write(fd, buf, *buf_size);
101 0 : if (num_bytes > 0) {
102 0 : if (num_bytes != *buf_size) {
103 0 : log_warn("Didn't write the right number of bytes?");
104 : }
105 0 : *buf_size = num_bytes;
106 0 : return WS_COMPLETE;
107 : } else {
108 0 : if (errno == EAGAIN) {
109 0 : return WS_INCOMPLETE_WRITE;
110 : } else {
111 0 : log_perror("Error writing to socket %d (rtn: %d, requested: %d)",
112 : fd, num_bytes, *buf_size);
113 0 : return WS_ERROR;
114 : }
115 : }
116 : }
|