GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/socket.c Lines: 47 51 92.2 %
Date: 2020-12-10 21:44:00 Branches: 22 24 91.7 %

Line Branch Exec Source
1
#include <errno.h> 				/* errno */
2
#include <string.h>             /* strerror, memset, strncpy, memcpy */
3
#include <unistd.h>             /* close */
4
#include <fcntl.h> 				/* fcntl */
5
6
#include <sys/types.h>          /* socket, setsockopt, accept, send, recv */
7
#include <sys/socket.h>         /* socket, setsockopt, inet_ntoa, accept */
8
#include <netinet/in.h>         /* sockaddr_in, inet_ntoa */
9
#include <arpa/inet.h>          /* htonl, htons, inet_ntoa */
10
11
#include "socket.h"
12
#include "log.h"
13
#include "error.h"
14
#include "pool.h"
15
#include "alloc.h"
16
#include "predict.h"
17
18
/**
19
 * Function that initializes a socket and store the filedescriptor.
20
 *
21
 * @param 	server	[server_t  **]	"The server instance"
22
 * @return 			[wss_error_t]   "The error status"
23
 */
24
8
wss_error_t WSS_socket_create(wss_server_t *server) {
25
8
    if ( unlikely(NULL == server) ) {
26
1
        WSS_log_fatal("No server structure given");
27
1
        return WSS_SOCKET_CREATE_ERROR;
28
    }
29
30
7
    if ( unlikely((server->fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) ) {
31
        WSS_log_fatal("Unable to create server filedescriptor: %s", strerror(errno));
32
        return WSS_SOCKET_CREATE_ERROR;
33
    }
34
35
    return WSS_SUCCESS;
36
}
37
38
/**
39
 * Function that enables reuse of the port if the server shuts down.
40
 *
41
 * @param 	fd		[int]		    "The filedescriptor associated to some user"
42
 * @return 			[wss_error_t]   "The error status"
43
 */
44
7
wss_error_t WSS_socket_reuse(int fd) {
45
7
    int reuse = 1;
46
7
    if ( unlikely((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) < 0) ){
47
1
        WSS_log_fatal("Unable to reuse port: %s", strerror(errno));
48
1
        return WSS_SOCKET_REUSE_ERROR;
49
    }
50
    return WSS_SUCCESS;
51
}
52
53
/**
54
 * Function that binds the socket to a specific port and chooses IPV6.
55
 *
56
 * @param 	server	[server_t *]	"The server instance"
57
 * @return 			[wss_error_t]   "The error status"
58
 */
59
8
wss_error_t WSS_socket_bind(wss_server_t *server) {
60
8
    if ( unlikely(NULL == server) ) {
61
1
        WSS_log_fatal("No server structure given");
62
1
        return WSS_SOCKET_BIND_ERROR;
63
    }
64
65
7
    if ( unlikely(server->port < 0 || server->port > 65535) ) {
66
1
        WSS_log_fatal("Server port must be within range [0, 65535]");
67
1
        server->fd = -1;
68
1
        return WSS_SOCKET_BIND_ERROR;
69
    }
70
71
    /**
72
     * Setting values of our server structure
73
     */
74
6
    memset((char *) &server->info, '\0', sizeof(server->info));
75
6
    server->info.sin6_family = AF_INET6;
76
6
    server->info.sin6_port   = htons(server->port);
77
6
    server->info.sin6_addr   = in6addr_any;
78
79
    /**
80
     * Binding address.
81
     */
82
6
    if ( unlikely((bind(server->fd, (struct sockaddr *) &server->info,
83
                    sizeof(server->info))) < 0) ) {
84
1
        WSS_log_fatal("Unable to bind socket to port: %s", strerror(errno));
85
1
        server->fd = -1;
86
1
        return WSS_SOCKET_BIND_ERROR;
87
    }
88
    return WSS_SUCCESS;
89
}
90
91
/**
92
 * Function that makes the socket non-blocking for both reads and writes.
93
 *
94
 * @param 	fd		[int]		    "The filedescriptor associated to some user"
95
 * @return 			[wss_error_t]   "The error status"
96
 */
97
5
wss_error_t WSS_socket_non_blocking(int fd) {
98
5
    int flags;
99
100
5
    if ( unlikely((flags = fcntl(fd, F_GETFL, 0)) < 0)) {
101
1
        WSS_log_fatal("Unable to fetch current filedescriptor flags: %s", strerror(errno));
102
1
        return WSS_SOCKET_NONBLOCKED_ERROR;
103
    }
104
105
4
    flags |= O_NONBLOCK;
106
107
4
    if ( unlikely((flags = fcntl(fd, F_SETFL, flags)) < 0) ) {
108
        WSS_log_fatal("Unable to set flags for filedescriptor: %s", strerror(errno));
109
        return WSS_SOCKET_NONBLOCKED_ERROR;
110
    }
111
112
    return WSS_SUCCESS;
113
}
114
115
/**
116
 * Function that makes the server start listening on the socket.
117
 *
118
 * @param 	fd		[int]	    	"The filedescriptor associated to some user"
119
 * @return 			[wss_error_t]   "The error status"
120
 */
121
4
wss_error_t WSS_socket_listen(int fd) {
122
    /**
123
     * Listen on the server socket for connections
124
     */
125
4
    if ( unlikely((listen(fd, SOMAXCONN)) < 0) ) {
126
1
        WSS_log_fatal("Unable to listen on filedescriptor: %s", strerror(errno));
127
1
        return WSS_SOCKET_LISTEN_ERROR;
128
    }
129
    return WSS_SUCCESS;
130
}
131
132
/**
133
 * Function that creates a threadpool which can be used handle traffic.
134
 *
135
 * @param 	server	[wss_server_t *]	"The server instance"
136
 * @return 			[wss_error_t]       "The error status"
137
 */
138
4
wss_error_t WSS_socket_threadpool(wss_server_t *server) {
139
4
    if ( unlikely(NULL == server) ) {
140
1
        WSS_log_fatal("No server structure given");
141
1
        return WSS_THREADPOOL_CREATE_ERROR;
142
    }
143
144
3
    if ( unlikely(NULL == server->config) ) {
145
1
        WSS_log_fatal("No server config structure");
146
1
        return WSS_THREADPOOL_CREATE_ERROR;
147
    }
148
149
    /**
150
     * Creating threadpool
151
     */
152
2
    if ( unlikely(NULL == (server->pool = threadpool_create(server->config->pool_workers,
153
                        server->config->size_thread, server->config->size_thread, 0))) ) {
154
1
        WSS_log_fatal("The threadpool failed to initialize");
155
1
        return WSS_THREADPOOL_CREATE_ERROR;
156
    }
157
158
    return WSS_SUCCESS;
159
}