Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / tool / client.cc
1 /* Copyright (c) 2014, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <openssl/base.h>
16
17 #include <string>
18 #include <vector>
19
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23
24 #if !defined(OPENSSL_WINDOWS)
25 #include <arpa/inet.h>
26 #include <fcntl.h>
27 #include <netdb.h>
28 #include <sys/select.h>
29 #include <unistd.h>
30 #else
31 #include <WinSock2.h>
32 #include <WS2tcpip.h>
33 typedef int socklen_t;
34 #endif
35
36 #include <openssl/err.h>
37 #include <openssl/ssl.h>
38
39 #include "internal.h"
40
41
42 static const struct argument kArguments[] = {
43     {
44      "-connect", true,
45      "The hostname and port of the server to connect to, e.g. foo.com:443",
46     },
47     {
48      "", false, "",
49     },
50 };
51
52 // Connect sets |*out_sock| to be a socket connected to the destination given
53 // in |hostname_and_port|, which should be of the form "www.example.com:123".
54 // It returns true on success and false otherwise.
55 static bool Connect(int *out_sock, const std::string &hostname_and_port) {
56   const size_t colon_offset = hostname_and_port.find_last_of(':');
57   std::string hostname, port;
58
59   if (colon_offset == std::string::npos) {
60     hostname = hostname_and_port;
61     port = "443";
62   } else {
63     hostname = hostname_and_port.substr(0, colon_offset);
64     port = hostname_and_port.substr(colon_offset + 1);
65   }
66
67   struct addrinfo hint, *result;
68   memset(&hint, 0, sizeof(hint));
69   hint.ai_family = AF_UNSPEC;
70   hint.ai_socktype = SOCK_STREAM;
71
72   int ret = getaddrinfo(hostname.c_str(), port.c_str(), &hint, &result);
73   if (ret != 0) {
74     fprintf(stderr, "getaddrinfo returned: %s\n", gai_strerror(ret));
75     return false;
76   }
77
78   bool ok = false;
79   char buf[256];
80
81   *out_sock =
82       socket(result->ai_family, result->ai_socktype, result->ai_protocol);
83   if (*out_sock < 0) {
84     perror("socket");
85     goto out;
86   }
87
88   switch (result->ai_family) {
89     case AF_INET: {
90       struct sockaddr_in *sin =
91           reinterpret_cast<struct sockaddr_in *>(result->ai_addr);
92       fprintf(stderr, "Connecting to %s:%d\n",
93               inet_ntop(result->ai_family, &sin->sin_addr, buf, sizeof(buf)),
94               ntohs(sin->sin_port));
95       break;
96     }
97     case AF_INET6: {
98       struct sockaddr_in6 *sin6 =
99           reinterpret_cast<struct sockaddr_in6 *>(result->ai_addr);
100       fprintf(stderr, "Connecting to [%s]:%d\n",
101               inet_ntop(result->ai_family, &sin6->sin6_addr, buf, sizeof(buf)),
102               ntohs(sin6->sin6_port));
103       break;
104     }
105   }
106
107   if (connect(*out_sock, result->ai_addr, result->ai_addrlen) != 0) {
108     perror("connect");
109     goto out;
110   }
111   ok = true;
112
113 out:
114   freeaddrinfo(result);
115   return ok;
116 }
117
118 static void PrintConnectionInfo(const SSL *ssl) {
119   const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
120
121   fprintf(stderr, "  Version: %s\n", SSL_get_version(ssl));
122   fprintf(stderr, "  Cipher: %s\n", SSL_CIPHER_get_name(cipher));
123   fprintf(stderr, "  Secure renegotiation: %s\n",
124           SSL_get_secure_renegotiation_support(ssl) ? "yes" : "no");
125 }
126
127 static bool SocketSetNonBlocking(int sock, bool is_non_blocking) {
128   bool ok;
129
130 #if defined(OPENSSL_WINDOWS)
131   u_long arg = is_non_blocking;
132   ok = 0 == ioctlsocket(sock, FIOBIO, &arg);
133 #else
134   int flags = fcntl(sock, F_GETFL, 0);
135   if (flags < 0) {
136     return false;
137   }
138   if (is_non_blocking) {
139     flags |= O_NONBLOCK;
140   } else {
141     flags &= ~O_NONBLOCK;
142   }
143   ok = 0 == fcntl(sock, F_SETFL, flags);
144 #endif
145   if (!ok) {
146     fprintf(stderr, "Failed to set socket non-blocking.\n");
147   }
148   return ok;
149 }
150
151 // PrintErrorCallback is a callback function from OpenSSL's
152 // |ERR_print_errors_cb| that writes errors to a given |FILE*|.
153 static int PrintErrorCallback(const char *str, size_t len, void *ctx) {
154   fwrite(str, len, 1, reinterpret_cast<FILE*>(ctx));
155   return 1;
156 }
157
158 bool TransferData(SSL *ssl, int sock) {
159   bool stdin_open = true;
160
161   fd_set read_fds;
162   FD_ZERO(&read_fds);
163
164   if (!SocketSetNonBlocking(sock, true)) {
165     return false;
166   }
167
168   for (;;) {
169     if (stdin_open) {
170       FD_SET(0, &read_fds);
171     }
172     FD_SET(sock, &read_fds);
173
174     int ret = select(sock + 1, &read_fds, NULL, NULL, NULL);
175     if (ret <= 0) {
176       perror("select");
177       return false;
178     }
179
180     if (FD_ISSET(0, &read_fds)) {
181       uint8_t buffer[512];
182       ssize_t n;
183
184       do {
185         n = read(0, buffer, sizeof(buffer));
186       } while (n == -1 && errno == EINTR);
187
188       if (n == 0) {
189         FD_CLR(0, &read_fds);
190         stdin_open = false;
191         shutdown(sock, SHUT_WR);
192         continue;
193       } else if (n < 0) {
194         perror("read from stdin");
195         return false;
196       }
197
198       if (!SocketSetNonBlocking(sock, false)) {
199         return false;
200       }
201       int ssl_ret = SSL_write(ssl, buffer, n);
202       if (!SocketSetNonBlocking(sock, true)) {
203         return false;
204       }
205
206       if (ssl_ret <= 0) {
207         int ssl_err = SSL_get_error(ssl, ssl_ret);
208         fprintf(stderr, "Error while writing: %d\n", ssl_err);
209         ERR_print_errors_cb(PrintErrorCallback, stderr);
210         return false;
211       } else if (ssl_ret != n) {
212         fprintf(stderr, "Short write from SSL_write.\n");
213         return false;
214       }
215     }
216
217     if (FD_ISSET(sock, &read_fds)) {
218       uint8_t buffer[512];
219       int ssl_ret = SSL_read(ssl, buffer, sizeof(buffer));
220
221       if (ssl_ret < 0) {
222         int ssl_err = SSL_get_error(ssl, ssl_ret);
223         if (ssl_err == SSL_ERROR_WANT_READ) {
224           continue;
225         }
226         fprintf(stderr, "Error while reading: %d\n", ssl_err);
227         ERR_print_errors_cb(PrintErrorCallback, stderr);
228         return false;
229       } else if (ssl_ret == 0) {
230         return true;
231       }
232
233       ssize_t n;
234       do {
235         n = write(1, buffer, ssl_ret);
236       } while (n == -1 && errno == EINTR);
237
238       if (n != ssl_ret) {
239         fprintf(stderr, "Short write to stderr.\n");
240         return false;
241       }
242     }
243   }
244 }
245
246 bool Client(const std::vector<std::string> &args) {
247   std::map<std::string, std::string> args_map;
248
249   if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
250     PrintUsage(kArguments);
251     return false;
252   }
253
254   SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
255
256   int sock = -1;
257   if (!Connect(&sock, args_map["-connect"])) {
258     return false;
259   }
260
261   BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
262   SSL *ssl = SSL_new(ctx);
263   SSL_set_bio(ssl, bio, bio);
264
265   int ret = SSL_connect(ssl);
266   if (ret != 1) {
267     int ssl_err = SSL_get_error(ssl, ret);
268     fprintf(stderr, "Error while connecting: %d\n", ssl_err);
269     ERR_print_errors_cb(PrintErrorCallback, stderr);
270     return false;
271   }
272
273   fprintf(stderr, "Connected.\n");
274   PrintConnectionInfo(ssl);
275
276   bool ok = TransferData(ssl, sock);
277
278   SSL_free(ssl);
279   SSL_CTX_free(ctx);
280   return ok;
281 }