First data retrieved from a server.
[ntbtls.git] / src / ntbtls-cli.c
1 /* ntbtls-cli.h - NTBTLS client test program
2  * Copyright (C) 2014 g10 Code GmbH
3  *
4  * This file is part of NTBTLS
5  *
6  * NTBTLS 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  * NTBTLS 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  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32
33 #include "ntbtls.h"
34
35 #define PGMNAME "ntbtls-cli"
36
37 static int verbose;
38 static int errorcount;
39
40 \f
41 /*
42  * Reporting functions.
43  */
44 static void
45 die (const char *format, ...)
46 {
47   va_list arg_ptr ;
48
49   fflush (stdout);
50 #ifdef HAVE_FLOCKFILE
51   flockfile (stderr);
52 #endif
53   fprintf (stderr, "%s: ", PGMNAME);
54   va_start (arg_ptr, format) ;
55   vfprintf (stderr, format, arg_ptr);
56   va_end (arg_ptr);
57   if (*format && format[strlen(format)-1] != '\n')
58     putc ('\n', stderr);
59 #ifdef HAVE_FLOCKFILE
60   funlockfile (stderr);
61 #endif
62   exit (1);
63 }
64
65
66 static void
67 fail (const char *format, ...)
68 {
69   va_list arg_ptr;
70
71   fflush (stdout);
72 #ifdef HAVE_FLOCKFILE
73   flockfile (stderr);
74 #endif
75   fprintf (stderr, "%s: ", PGMNAME);
76   va_start (arg_ptr, format);
77   vfprintf (stderr, format, arg_ptr);
78   va_end (arg_ptr);
79   if (*format && format[strlen(format)-1] != '\n')
80     putc ('\n', stderr);
81 #ifdef HAVE_FLOCKFILE
82   funlockfile (stderr);
83 #endif
84   errorcount++;
85   if (errorcount >= 50)
86     die ("stopped after 50 errors.");
87 }
88
89
90 static void
91 info (const char *format, ...)
92 {
93   va_list arg_ptr;
94
95   if (!verbose)
96     return;
97 #ifdef HAVE_FLOCKFILE
98   flockfile (stderr);
99 #endif
100   fprintf (stderr, "%s: ", PGMNAME);
101   va_start (arg_ptr, format);
102   vfprintf (stderr, format, arg_ptr);
103   if (*format && format[strlen(format)-1] != '\n')
104     putc ('\n', stderr);
105   va_end (arg_ptr);
106 #ifdef HAVE_FLOCKFILE
107   funlockfile (stderr);
108 #endif
109 }
110
111
112 \f
113 static int
114 connect_server (const char *server, unsigned short port)
115 {
116   gpg_error_t err;
117   int sock = -1;
118   struct sockaddr_in addr;
119   struct hostent *host;
120
121   addr.sin_family = AF_INET;
122   addr.sin_port = htons (port);
123   host = gethostbyname ((char*)server);
124   if (!host)
125     {
126       err = gpg_error_from_syserror ();
127       fail ("host '%s' not found: %s\n", server, gpg_strerror (err));
128       return -1;
129     }
130
131   addr.sin_addr = *(struct in_addr*)host->h_addr;
132
133   sock = socket (AF_INET, SOCK_STREAM, 0);
134   if (sock == -1)
135     {
136       err = gpg_error_from_syserror ();
137       die ("error creating socket: %s\n", gpg_strerror (err));
138       return -1;
139     }
140
141   if (connect (sock, (struct sockaddr *)&addr, sizeof addr) == -1)
142     {
143       err = gpg_error_from_syserror ();
144       fail ("error connecting '%s': %s\n", server, gpg_strerror (err));
145       close (sock);
146       return -1;
147     }
148
149   info ("connected to '%s' port %hu\n", server, port);
150
151   return sock;
152 }
153
154
155 static int
156 connect_estreams (const char *server, int port,
157                   estream_t *r_in, estream_t *r_out)
158 {
159   gpg_error_t err;
160   int sock;
161
162   *r_in = *r_out = NULL;
163
164   sock = connect_server (server, port);
165   if (sock == -1)
166     return gpg_error (GPG_ERR_GENERAL);
167   *r_in = es_fdopen_nc (sock, "rb");
168   if (!*r_in)
169     {
170       err = gpg_error_from_syserror ();
171       close (sock);
172       return err;
173     }
174   *r_out = es_fdopen (sock, "wb");
175   if (!*r_out)
176     {
177       err = gpg_error_from_syserror ();
178       es_fclose (*r_in);
179       *r_in = NULL;
180       close (sock);
181       return err;
182     }
183
184   return 0;
185 }
186
187
188 \f
189 static void
190 simple_client (const char *server, int port)
191 {
192   gpg_error_t err;
193   ntbtls_t tls;
194   estream_t inbound, outbound;
195   estream_t readfp, writefp;
196   int c;
197
198   err = ntbtls_new (&tls, NTBTLS_CLIENT);
199   if (err)
200     die ("ntbtls_init failed: %s <%s>\n",
201          gpg_strerror (err), gpg_strsource (err));
202
203   err = connect_estreams (server, port, &inbound, &outbound);
204   if (err)
205     die ("error connecting server: %s <%s>\n",
206          gpg_strerror (err), gpg_strsource (err));
207
208   err = ntbtls_set_transport (tls, inbound, outbound);
209   if (err)
210     die ("ntbtls_set_transport failed: %s <%s>\n",
211          gpg_strerror (err), gpg_strsource (err));
212
213   err = ntbtls_get_stream (tls, &readfp, &writefp);
214   if (err)
215     die ("ntbtls_get_stream failed: %s <%s>\n",
216          gpg_strerror (err), gpg_strsource (err));
217
218   info ("starting handshake");
219   while ((err = ntbtls_handshake (tls)))
220     {
221       info ("handshake error: %s <%s>", gpg_strerror (err),gpg_strsource (err));
222       switch (gpg_err_code (err))
223         {
224         default:
225           break;
226         }
227       die ("handshake failed");
228     }
229   info ("handshake done");
230
231   do
232     {
233       es_fputs ("GET / HTTP/1.0\r\n\r\n", writefp);
234       es_fflush (writefp);
235       while (/* es_pending (readfp) && */(c = es_fgetc (readfp)) != EOF)
236         putchar (c);
237     }
238   while (c != EOF);
239
240   ntbtls_release (tls);
241   es_fclose (inbound);
242   es_fclose (outbound);
243 }
244
245
246
247 int
248 main (int argc, char **argv)
249 {
250   int last_argc = -1;
251   int debug_level = 0;
252   int port = 443;
253
254   if (argc)
255     { argc--; argv++; }
256   while (argc && last_argc != argc )
257     {
258       last_argc = argc;
259       if (!strcmp (*argv, "--"))
260         {
261           argc--; argv++;
262           break;
263         }
264       else if (!strcmp (*argv, "--version"))
265         {
266           printf ("%s\n", ntbtls_check_version (NULL));
267           if (verbose)
268             printf ("%s", ntbtls_check_version ("\001\001"));
269           return 0;
270         }
271       else if (!strcmp (*argv, "--verbose"))
272         {
273           verbose = 1;
274           argc--; argv++;
275         }
276       else if (!strcmp (*argv, "--debug"))
277         {
278           verbose = 1;
279           argc--; argv++;
280           if (argc)
281             {
282               debug_level = atoi (*argv);
283               argc--; argv++;
284             }
285           else
286             debug_level = 1;
287         }
288       else if (!strcmp (*argv, "--port"))
289         {
290           argc--; argv++;
291           if (argc)
292             {
293               port = atoi (*argv);
294               argc--; argv++;
295             }
296           else
297             port = 8443;
298         }
299       else if (!strncmp (*argv, "--", 2) && (*argv)[2])
300         die ("Invalid option '%s'\n", *argv);
301     }
302
303   if (!ntbtls_check_version (PACKAGE_VERSION))
304     die ("NTBTLS library too old (need %s, have %s)\n",
305          PACKAGE_VERSION, ntbtls_check_version (NULL));
306
307   if (debug_level)
308     ntbtls_set_debug (debug_level, NULL, NULL);
309
310   simple_client (argc? *argv : "localhost", port);
311   return 0;
312 }