LCOV - code coverage report
Current view: top level - msus/webserver - dbops.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 100 135 74.1 %
Date: 2018-01-11 Functions: 10 10 100.0 %

          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             : }

Generated by: LCOV version 1.10