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 163 : ssize_t client_send_raw(LOGGER log, CONNECTION* client, char* data, ssize_t bytes){
8 163 : ssize_t bytes_sent = 0, bytes_written = 0, bytes_left;
9 :
10 : //early bail saves some syscalls
11 163 : if(bytes == 0){
12 0 : return 0;
13 : }
14 :
15 163 : if(bytes < 0){
16 0 : bytes=strlen(data);
17 : }
18 :
19 163 : logprintf(log, LOG_DEBUG, "Sending %d raw bytes\n", bytes);
20 :
21 : do{
22 163 : bytes_left = bytes - bytes_sent;
23 163 : if(bytes_left > MAX_SEND_CHUNK){
24 0 : bytes_left = MAX_SEND_CHUNK;
25 : }
26 : #ifndef CMAIL_NO_TLS
27 163 : switch(client->tls_mode){
28 : case TLS_NONE:
29 44 : bytes_written = send(client->fd, data + bytes_sent, bytes_left, 0);
30 44 : break;
31 : case TLS_NEGOTIATE:
32 0 : logprintf(log, LOG_WARNING, "Not sending data while negotiation is in progress\n");
33 0 : return bytes_sent;
34 : case TLS_ONLY:
35 119 : bytes_written = gnutls_record_send(client->tls_session, data + bytes_sent, bytes_left);
36 119 : break;
37 : }
38 : #else
39 : bytes_written = send(client->fd, data + bytes_sent, bytes_left, 0);
40 : #endif
41 :
42 163 : if(bytes_written + bytes_sent < bytes){
43 0 : logprintf(log, LOG_DEBUG, "Partial write (%d for %d/%d)\n", bytes_written, bytes_sent, bytes);
44 : }
45 :
46 163 : if(bytes_written < 0){
47 : #ifndef CMAIL_NO_TLS
48 0 : if(client->tls_mode == TLS_NONE){
49 : #endif
50 0 : if(errno != EAGAIN){
51 0 : logprintf(log, LOG_ERROR, "Write failed: %s\n", strerror(errno));
52 0 : break;
53 : }
54 : #ifndef CMAIL_NO_TLS
55 : }
56 : else{
57 0 : if(bytes_written != GNUTLS_E_INTERRUPTED && bytes_written != GNUTLS_E_AGAIN){
58 0 : logprintf(log, LOG_ERROR, "TLS Write failed: %s\n", gnutls_strerror(bytes_written));
59 0 : break;
60 : }
61 : }
62 : #endif
63 : }
64 : else{
65 163 : bytes_sent += bytes_written;
66 : }
67 : }
68 163 : while(bytes_sent < bytes);
69 :
70 163 : logprintf(log, LOG_ALL_IO, "<< %.*s", bytes, data);
71 163 : logprintf(log, LOG_DEBUG, "Sent %d bytes of %d\n", bytes_sent, bytes);
72 :
73 163 : return bytes_sent;
74 : }
75 :
76 163 : int client_send(LOGGER log, CONNECTION* client, char* fmt, ...){
77 : va_list args, copy;
78 163 : ssize_t bytes = 0;
79 : char static_send_buffer[STATIC_SEND_BUFFER_LENGTH + 1];
80 163 : char* dynamic_send_buffer = NULL;
81 163 : char* send_buffer = static_send_buffer;
82 :
83 163 : va_start(args, fmt);
84 163 : va_copy(copy, args);
85 : //check if the buffer was long enough, if not, allocate a new one
86 163 : bytes = vsnprintf(send_buffer, STATIC_SEND_BUFFER_LENGTH, fmt, args);
87 163 : va_end(args);
88 :
89 163 : if(bytes >= STATIC_SEND_BUFFER_LENGTH){
90 0 : dynamic_send_buffer = calloc(bytes + 2, sizeof(char));
91 0 : if(!dynamic_send_buffer){
92 0 : logprintf(log, LOG_ERROR, "Failed to allocate dynamic send buffer\n");
93 0 : va_end(copy);
94 0 : return -1;
95 : }
96 0 : send_buffer = dynamic_send_buffer;
97 0 : bytes = vsnprintf(send_buffer, bytes + 1, fmt, copy);
98 : }
99 163 : va_end(copy);
100 :
101 163 : if(bytes < 0){
102 0 : logprintf(log, LOG_ERROR, "Failed to render client output data string\n");
103 0 : return -1;
104 : }
105 :
106 163 : bytes = client_send_raw(log, client, send_buffer, bytes);
107 :
108 163 : if(dynamic_send_buffer){
109 0 : free(dynamic_send_buffer);
110 : }
111 :
112 163 : return bytes;
113 : }
|