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 <stdlib.h>
21 : #include "logging.h"
22 : #include <sys/socket.h>
23 : #include <netinet/in.h>
24 : #include <strings.h>
25 : #include <arpa/inet.h>
26 : #include <unistd.h>
27 : #include "webserver/connection-handler.h"
28 :
29 : #ifndef MAX_FILE_SIZE
30 : #define MAX_FILE_SIZE (long)(1 * (1 << 29))
31 : #endif
32 : #define JUMP_SIZE (1 << 14)
33 :
34 : int db_num_files = -1;
35 : struct sockaddr_in db_addr;
36 :
37 : struct mock_file {
38 : int n_chunks;
39 : int *chunk_size;
40 : char **data;
41 : };
42 :
43 29 : long allocate_file(struct mock_file *file, long file_size) {
44 29 : int n_chunks = file_size / INT_MAX + 1;
45 29 : file->n_chunks = n_chunks;
46 29 : file->chunk_size = malloc(sizeof(int) * n_chunks);
47 29 : long amount_allocated = 0;
48 29 : int chunk_size = INT_MAX;
49 29 : file->data = malloc(sizeof(char*) * n_chunks);
50 58 : for (int i=0; amount_allocated < file_size; i++) {
51 29 : if (amount_allocated + chunk_size > file_size) {
52 29 : long chunk_tmp = (file_size - amount_allocated);
53 29 : if (chunk_tmp > (long)(INT_MAX)) {
54 0 : printf("Warning: Chunk size too big!\n");
55 : }
56 29 : chunk_size = (int)chunk_tmp;
57 : }
58 29 : file->chunk_size[i] = chunk_size;
59 29 : file->data[i] = malloc(chunk_size);
60 29 : amount_allocated += chunk_size;
61 29 : memset(file->data[i], 0, chunk_size);
62 : }
63 29 : return amount_allocated;
64 : }
65 :
66 1 : long access_file(struct mock_file *file, long total_size) {
67 1 : long accessed = 0;
68 2 : for (int chunk = 0; accessed < total_size; chunk++) {
69 1 : int chunk_size = file->chunk_size[chunk];
70 1 : char *data = file->data[chunk];
71 2 : for (int i = 0; i < chunk_size; i += JUMP_SIZE) {
72 1 : data[i]++;
73 : }
74 1 : accessed += (long)chunk_size;
75 : }
76 1 : return accessed;
77 : }
78 :
79 29 : void init_db(char *ip, int port, int n_files) {
80 29 : db_num_files = n_files;
81 29 : bzero((char*)&db_addr, sizeof(db_addr));
82 29 : db_addr.sin_family = AF_INET;
83 29 : inet_pton(AF_INET, ip, &(db_addr.sin_addr));
84 29 : db_addr.sin_port = htons(port);
85 29 : }
86 :
87 29 : void *allocate_db_memory() {
88 29 : struct mock_file *file = malloc(sizeof(*file));
89 29 : allocate_file(file, MAX_FILE_SIZE);
90 29 : return (void*)file;
91 : }
92 :
93 29 : void free_db_memory(void *memory) {
94 29 : struct mock_file *file = memory;
95 58 : for (int i=0; i <file->n_chunks; i++) {
96 29 : free(file->data[i]);
97 : }
98 29 : free(file->chunk_size);
99 29 : free(file->data);
100 29 : free(file);
101 29 : }
102 :
103 :
104 2 : int init_db_socket() {
105 2 : int db_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
106 2 : if (db_fd < 0) {
107 0 : log_error("failure opening socket");
108 0 : return -1;
109 : }
110 2 : int optval = 1;
111 2 : if (setsockopt(db_fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) < 0) {
112 0 : log_error("failed to set SO_REUSEPORT");
113 : }
114 2 : if (setsockopt(db_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
115 0 : log_error("failed to set SO_REUSEADDR");
116 : }
117 : //add_to_epoll(0, db_fd, 0);
118 2 : return db_fd;
119 : }
120 :
121 2 : int connect_to_db(struct db_state *state) {
122 2 : if (state->db_fd <= 0) {
123 2 : state->db_fd = init_db_socket();
124 2 : if (state->db_fd == -1) {
125 0 : return -1;
126 : }
127 : }
128 2 : int rtn = connect(state->db_fd, (struct sockaddr*)&db_addr, sizeof(db_addr)) < 0;
129 2 : if (rtn < 0) {
130 0 : if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
131 0 : log(LOG_DB_OPS, "Connection in progress..");
132 0 : return 1;
133 : } else {
134 0 : log_perror("Connect to socket failed");
135 0 : close(state->db_fd);
136 0 : return -1;
137 : }
138 : }
139 2 : int db_param = rand() % db_num_files;
140 2 : sprintf(state->db_req, "%d", db_param);
141 2 : return 0;
142 : }
143 :
144 2 : int send_to_db(struct db_state *state) {
145 2 : if (send(state->db_fd, state->db_req, strlen(state->db_req), 0) == -1) {
146 1 : if (errno == EAGAIN || errno == EWOULDBLOCK) {
147 0 : return 1;
148 : } else {
149 1 : log_perror("Error sending to database on fd %d", state->db_fd);
150 1 : return -1;
151 : }
152 : }
153 1 : return 0;
154 : }
155 :
156 : #define MAX_DB_RCV_LEN 64
157 :
158 2 : int recv_from_db(struct db_state *state) {
159 : char rcv[MAX_DB_RCV_LEN];
160 2 : socklen_t addrlen = sizeof(db_addr);
161 2 : int rtn = recvfrom(state->db_fd, rcv, MAX_DB_RCV_LEN, 0,
162 : (struct sockaddr*)&db_addr, &addrlen);
163 :
164 2 : if (rtn < 0) {
165 1 : if (errno == EAGAIN || errno == EWOULDBLOCK) {
166 1 : return 1;
167 : } else {
168 0 : log_perror("Error receiving from database");
169 0 : return -1;
170 : }
171 : }
172 :
173 : //long file_size = atol(rcv);
174 1 : struct mock_file *local_file = state->data;
175 :
176 1 : access_file(local_file, MAX_FILE_SIZE);
177 1 : close(state->db_fd);
178 1 : state->db_fd = 0;
179 1 : return 0;
180 : }
181 :
182 3 : int query_db(struct db_state *state) {
183 3 : if (db_num_files == -1) {
184 0 : log_error("Database is not initialized");
185 0 : return WS_ERROR;
186 :
187 : }
188 :
189 : int rtn;
190 3 : switch (state->status) {
191 : case DB_NO_CONNECTION:
192 : case DB_CONNECTING:
193 2 : rtn = connect_to_db(state);
194 2 : if (rtn == -1) {
195 0 : state->status = DB_ERR;
196 0 : return WS_ERROR;
197 2 : } else if (rtn == 1) {
198 0 : state->status = DB_CONNECTING;
199 0 : return WS_INCOMPLETE_WRITE;
200 2 : } else if (rtn == 0) {
201 2 : state->status = DB_SEND;
202 : // Continue on...
203 : } else {
204 0 : log_error("Unknown status %d", rtn);
205 0 : state->status = DB_ERR;
206 0 : return WS_ERROR;
207 : }
208 : case DB_SEND:
209 2 : rtn = send_to_db(state);
210 2 : if (rtn == -1) {
211 1 : state->status = DB_ERR;
212 1 : return WS_ERROR;
213 1 : } else if (rtn == 1) {
214 0 : return WS_INCOMPLETE_WRITE;
215 1 : } else if (rtn == 0) {
216 1 : state->status = DB_RECV;
217 : // Continue on...
218 : } else {
219 0 : log_error("Unknown status %d", rtn);
220 0 : state->status = DB_ERR;
221 0 : return WS_ERROR;
222 : }
223 : case DB_RECV:
224 2 : rtn = recv_from_db(state);
225 2 : if (rtn == -1) {
226 0 : state->status = DB_ERR;
227 0 : return WS_ERROR;
228 2 : } else if (rtn == 1) {
229 1 : return WS_INCOMPLETE_READ;
230 1 : } else if (rtn == 0) {
231 1 : state->status = DB_DONE;
232 1 : return WS_COMPLETE;
233 : } else {
234 0 : state->status = DB_ERR;
235 0 : log_error("Unknown status %d", rtn);
236 0 : return WS_ERROR;
237 : }
238 : default:
239 0 : log_error("Unhandled state: %d", state->status);
240 0 : return WS_ERROR;
241 : }
242 :
243 : }
|