Line data Source code
1 : /* This file is part of the cmail project (http://cmail.rocks/)
2 : * (c) 2015 Fabian "cbdev" Stumpf
3 : * License: Simplified BSD (2-Clause)
4 : * For further information, consult LICENSE.txt
5 : */
6 :
7 107 : ssize_t network_read(LOGGER log, CONNECTION* client, char* buffer, unsigned bytes){
8 : int status;
9 :
10 : #ifndef CMAIL_NO_TLS
11 107 : switch(client->tls_mode){
12 : case TLS_NONE:
13 : //non-tls client
14 26 : return recv(client->fd, buffer, bytes, 0);
15 : case TLS_NEGOTIATE:
16 : //tls handshake not completed
17 20 : status = gnutls_handshake(client->tls_session);
18 20 : if(status){
19 10 : if(gnutls_error_is_fatal(status)){
20 0 : logprintf(log, LOG_ERROR, "TLS Handshake reported fatal error: %s\n", gnutls_strerror(status));
21 0 : return -2;
22 : }
23 10 : logprintf(log, LOG_WARNING, "TLS Handshake reported nonfatal error: %s\n", gnutls_strerror(status));
24 10 : return -1;
25 : }
26 :
27 10 : logprintf(log, LOG_INFO, "TLS Handshake completed\n");
28 10 : return 0;
29 : case TLS_ONLY:
30 : //read with tls
31 61 : return gnutls_record_recv(client->tls_session, buffer, bytes);
32 : }
33 : #else
34 : return recv(client->fd, buffer, bytes, 0);
35 : #endif
36 :
37 0 : logprintf(log, LOG_ERROR, "Network read with invalid TLSMODE\n");
38 0 : return -2;
39 : }
40 :
41 0 : int network_connect(LOGGER log, char* host, uint16_t port){
42 0 : int sockfd = -1, error;
43 : char port_str[20];
44 : struct addrinfo hints;
45 : struct addrinfo* head;
46 : struct addrinfo* iter;
47 :
48 0 : memset(&hints, 0, sizeof hints);
49 0 : hints.ai_family = AF_UNSPEC;
50 0 : hints.ai_socktype = SOCK_STREAM;
51 :
52 0 : snprintf(port_str, sizeof(port_str), "%d", port);
53 :
54 0 : error = getaddrinfo(host, port_str, &hints, &head);
55 0 : if(error){
56 0 : logprintf(log, LOG_WARNING, "getaddrinfo: %s\r\n", gai_strerror(error));
57 0 : return -1;
58 : }
59 :
60 0 : for(iter = head; iter; iter = iter->ai_next){
61 0 : sockfd = socket(iter->ai_family, iter->ai_socktype, iter->ai_protocol);
62 0 : if(sockfd < 0){
63 0 : continue;
64 : }
65 :
66 0 : error = connect(sockfd, iter->ai_addr, iter->ai_addrlen);
67 0 : if(error != 0){
68 0 : close(sockfd);
69 0 : continue;
70 : }
71 :
72 0 : break;
73 : }
74 :
75 0 : freeaddrinfo(head);
76 0 : iter = NULL;
77 :
78 0 : if(sockfd < 0){
79 0 : logprintf(log, LOG_WARNING, "Failed to create client socket: %s\n", strerror(errno));
80 0 : return -1;
81 : }
82 :
83 0 : if(error != 0){
84 0 : logprintf(log, LOG_WARNING, "Failed to connect: %s\n", strerror(errno));
85 0 : return -1;
86 : }
87 :
88 0 : return sockfd;
89 : }
90 :
91 4 : int network_listener(LOGGER log, char* bindhost, char* port){
92 4 : int fd = -1, status, yes = 1;
93 : struct addrinfo hints;
94 : struct addrinfo* info;
95 : struct addrinfo* addr_it;
96 :
97 4 : memset(&hints, 0, sizeof(hints));
98 :
99 4 : hints.ai_family = AF_UNSPEC;
100 4 : hints.ai_socktype = SOCK_STREAM;
101 4 : hints.ai_flags = AI_PASSIVE;
102 :
103 4 : status = getaddrinfo(bindhost, port, &hints, &info);
104 4 : if(status != 0){
105 0 : logprintf(log, LOG_ERROR, "Failed to get socket info for %s port %s: %s\n", bindhost, port, gai_strerror(status));
106 0 : return -1;
107 : }
108 :
109 4 : for(addr_it = info; addr_it != NULL; addr_it = addr_it->ai_next){
110 4 : fd = socket(addr_it->ai_family, addr_it->ai_socktype, addr_it->ai_protocol);
111 4 : if(fd < 0){
112 0 : continue;
113 : }
114 :
115 4 : if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(yes)) < 0){
116 2 : logprintf(log, LOG_WARNING, "Failed to set IPV6_V6ONLY on socket for %s port %s: %s\n", bindhost, port, strerror(errno));
117 : }
118 :
119 4 : yes = 1;
120 4 : if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0){
121 0 : logprintf(log, LOG_WARNING, "Failed to set SO_REUSEADDR on socket\n");
122 : }
123 :
124 4 : status = bind(fd, addr_it->ai_addr, addr_it->ai_addrlen);
125 4 : if(status < 0){
126 0 : close(fd);
127 0 : continue;
128 : }
129 :
130 4 : break;
131 : }
132 :
133 4 : freeaddrinfo(info);
134 :
135 4 : if(!addr_it){
136 0 : logprintf(log, LOG_ERROR, "Failed to create listening socket for %s port %s\n", bindhost, port);
137 0 : return -1;
138 : }
139 :
140 4 : status = listen(fd, LISTEN_QUEUE_LENGTH);
141 4 : if(status < 0){
142 0 : logprintf(log, LOG_ERROR, "Failed to listen on socket: %s", strerror(errno));
143 0 : close(fd);
144 0 : return -1;
145 : }
146 :
147 4 : return fd;
148 : }
|