summaryrefslogtreecommitdiff
path: root/vchat-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'vchat-connection.c')
-rw-r--r--vchat-connection.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/vchat-connection.c b/vchat-connection.c
new file mode 100644
index 0000000..e3d79e9
--- /dev/null
+++ b/vchat-connection.c
@@ -0,0 +1,223 @@
1/*
2 * vchat-client - alpha version
3 * vchat-connection.c - handling of server connection and tls library dispatch
4 *
5 * Copyright (C) 2022 Dirk Engling <erdgeist@erdgeist.org>
6 *
7 * This program is free software. It can be redistributed and/or modified,
8 * provided that this copyright notice is kept intact. This program is
9 * distributed in the hope that it will be useful, but without any warranty;
10 * without even the implied warranty of merchantability or fitness for a
11 * particular purpose. In no event shall the copyright holder be liable for
12 * any direct, indirect, incidental or special damages arising in any way out
13 * of the use of this software.
14 *
15 */
16
17#include <stdlib.h>
18#include <stddef.h>
19#include <string.h>
20#include <stdio.h>
21#include <unistd.h>
22#include <netdb.h>
23#include <errno.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27
28/* For tilde_expand */
29#include <readline/readline.h>
30
31#include "vchat.h"
32#include "vchat-connection.h"
33#include "vchat-tls.h"
34
35static int serverfd = -1;
36unsigned int want_tcp_keepalive = 0;
37
38/* Generic tcp connector, blocking */
39static int connect_tcp_socket( const char *server, const char *port ) {
40 struct addrinfo hints, *res, *res0;
41 int s, error;
42
43 memset(&hints, 0, sizeof(hints));
44 hints.ai_family = PF_UNSPEC;
45 hints.ai_socktype = SOCK_STREAM;
46 error = getaddrinfo( server, port, &hints, &res0 );
47 if (error) return -1;
48 s = -1;
49 for (res = res0; res; res = res->ai_next) {
50 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
51 if (s < 0) continue;
52 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
53 close(s);
54 s = -1;
55 continue;
56 }
57 break; /* okay we got one */
58 }
59 freeaddrinfo(res0);
60
61 if (want_tcp_keepalive) {
62 int one=1;
63 setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,&one,sizeof(one));
64 }
65 return s;
66}
67
68/* Return a tilde expanded path in a malloced buffer or NULL */
69static char *get_tilde_expanded(confopt opt) {
70 char *str = getstroption (opt);
71 if (!str)
72 return str;
73 if (str[0] == '~')
74 return tilde_expand (str);
75 return strdup(str);
76}
77
78/* connects to server */
79int
80vc_connect (const char *server, const char *port)
81{
82 /* vchat connection x509 store */
83 vc_x509store_t *vc_store;
84
85 /* pointer to tilde-expanded certificate/keyfile-names */
86 char *certfile = NULL;
87
88 /* Connect to the server */
89 serverfd = connect_tcp_socket( server, port );
90 if( serverfd < 0 ) {
91 /* inform user */
92 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port );
93 writechan (tmpstr);
94 return -1;
95 }
96
97 if (!getintoption(CF_USESSL))
98 return 0;
99
100 /* If SSL is requested, get our ssl-BIO running */
101 vc_store = vc_init_x509store();
102 if( !vc_store ) {
103 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_ERR), "Out of memory" );
104 writechan (tmpstr);
105 return -1;
106 }
107
108 /* get name of certificate file */
109 certfile = get_tilde_expanded (CF_CERTFILE);
110 /* do we have a certificate file? */
111 if (certfile) {
112 /* get name of key file */
113 char *keyfile = get_tilde_expanded (CF_KEYFILE);
114
115 vc_x509store_setflags(vc_store, VC_X509S_USE_CERTIFICATE);
116 vc_x509store_setcertfile(vc_store, certfile);
117
118 vc_x509store_set_pkeycb(vc_store, (vc_askpass_cb_t)passprompt);
119 /* if we don't have a key file, the key may be in the cert file */
120 vc_x509store_setkeyfile(vc_store, keyfile ? keyfile : certfile);
121
122 free(keyfile);
123 free(certfile);
124 }
125
126 if (getintoption(CF_VERIFYSSL)) {
127 /* get name of key file */
128 char *cafile = get_tilde_expanded (CF_CAFILE);
129 if (cafile) {
130 vc_x509store_setflags(vc_store, VC_X509S_NODEF_CAFILE);
131 vc_x509store_setcafile(vc_store, cafile);
132 }
133 vc_x509store_setflags(vc_store, VC_X509S_SSL_VERIFY_PEER);
134 free(cafile);
135 }
136
137 /* upgrade our plain BIO to ssl */
138 int result = vc_tls_connect( serverfd, vc_store );
139 vc_cleanup_x509store(vc_store);
140
141 if (result) {
142 close(serverfd);
143 serverfd = -1;
144 errno = EIO;
145 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port );
146 writechan (tmpstr);
147 return -1;
148 }
149
150 /* inform user */
151 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CONNECTED), server, port);
152 writechan (tmpstr);
153
154#ifdef DEBUG
155 dumpfile = fopen( "dumpfile", "a");
156#endif
157
158 /* if we didn't fail until now, we've got a connection. */
159 return 0;
160}
161
162/* Poll for activity on the socket or stdin */
163int vc_poll (int timeout_seconds) {
164 fd_set readfds;
165 FD_ZERO (&readfds);
166 FD_SET (0, &readfds);
167 if (serverfd != -1)
168 FD_SET (serverfd, &readfds);
169 struct timeval tv = { timeout_seconds, 0};
170 int result = select (serverfd + 2, &readfds, NULL, NULL, &tv);
171 if (result <= 0)
172 return result;
173 result = FD_ISSET (0, &readfds) ? 1 : 0;
174 if (serverfd != -1)
175 result += FD_ISSET (serverfd, &readfds) ? 2 : 0;
176 return result;
177}
178
179/* disconnect from server */
180void
181vc_disconnect () {
182 if (serverfd > 0) {
183 close(serverfd);
184 serverfd = -1;
185 }
186 vc_tls_cleanup();
187 loggedin = 0;
188}
189
190void
191vc_sendmessage (const char *msg)
192{
193#ifdef DEBUG
194 /* debugging? log network output! */
195 fprintf (dumpfile, ">| %s (%zd)\n", msg, strlen(msg));
196#endif
197
198 if (getintoption(CF_USESSL)) {
199 /* send data to server */
200 if (vc_tls_sendmessage (msg, strlen (msg)) != strlen (msg))
201 writecf (FS_ERR,"Message sending fuzzy.");
202
203 /* send line termination to server */
204 if (vc_tls_sendmessage ("\r\n", 2) != 2)
205 writecf (FS_ERR,"Message sending fuzzy.");
206 } else {
207 /* send data to server */
208 if (write (serverfd, msg, strlen (msg)) != strlen (msg))
209 writecf (FS_ERR,"Message sending fuzzy.");
210
211 /* send line termination to server */
212 if (write (serverfd, "\r\n", 2) != 2)
213 writecf (FS_ERR,"Message sending fuzzy.");
214 }
215}
216
217ssize_t
218vc_receivemessage (char *buffer, size_t size) {
219 if (getintoption(CF_USESSL))
220 return vc_tls_receivemessage (buffer, size);
221 else
222 return read(serverfd, buffer, size);
223}