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#define _BSD_SOURCE
16
17#include <arpa/inet.h>
18#include <fcntl.h>
19#include <netinet/in.h>
20#include <string.h>
21#include <sys/socket.h>
22#include <unistd.h>
23
24#include <openssl/bio.h>
25#include <openssl/crypto.h>
26#include <openssl/err.h>
27
28
29static int test_socket_connect(void) {
30  int listening_sock = socket(AF_INET, SOCK_STREAM, 0);
31  int sock;
32  struct sockaddr_in sin;
33  socklen_t sockaddr_len = sizeof(sin);
34  static const char kTestMessage[] = "test";
35  char hostname[80], buf[5];
36  BIO *bio;
37
38  memset(&sin, 0, sizeof(sin));
39  sin.sin_family = AF_INET;
40  if (!inet_aton("127.0.0.1", &sin.sin_addr)) {
41    perror("inet_aton");
42    return 0;
43  }
44
45  if (bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
46    perror("bind");
47    return 0;
48  }
49
50  if (listen(listening_sock, 1)) {
51    perror("listen");
52    return 0;
53  }
54
55  if (getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len) ||
56      sockaddr_len != sizeof(sin)) {
57    perror("getsockname");
58    return 0;
59  }
60
61  snprintf(hostname, sizeof(hostname), "%s:%d", "127.0.0.1",
62           ntohs(sin.sin_port));
63  bio = BIO_new_connect(hostname);
64  if (!bio) {
65    fprintf(stderr, "BIO_new_connect failed.\n");
66    return 0;
67  }
68
69  if (BIO_write(bio, kTestMessage, sizeof(kTestMessage)) !=
70      sizeof(kTestMessage)) {
71    fprintf(stderr, "BIO_write failed.\n");
72    BIO_print_errors_fp(stderr);
73    return 0;
74  }
75
76  sock = accept(listening_sock, (struct sockaddr *) &sin, &sockaddr_len);
77  if (sock < 0) {
78    perror("accept");
79    return 0;
80  }
81
82  if (read(sock, buf, sizeof(buf)) != sizeof(kTestMessage)) {
83    perror("read");
84    return 0;
85  }
86
87  if (memcmp(buf, kTestMessage, sizeof(kTestMessage))) {
88    return 0;
89  }
90
91  close(sock);
92  close(listening_sock);
93  BIO_free(bio);
94
95  return 1;
96}
97
98static int test_printf(void) {
99  /* Test a short output, a very long one, and various sizes around
100   * 256 (the size of the buffer) to ensure edge cases are correct. */
101  static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
102  BIO *bio;
103  char string[1024];
104  int ret;
105  const uint8_t *contents;
106  size_t i, len;
107
108  bio = BIO_new(BIO_s_mem());
109  if (!bio) {
110    fprintf(stderr, "BIO_new failed\n");
111    return 0;
112  }
113
114  for (i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
115    if (kLengths[i] >= sizeof(string)) {
116      fprintf(stderr, "Bad test string length\n");
117      return 0;
118    }
119    memset(string, 'a', sizeof(string));
120    string[kLengths[i]] = '\0';
121
122    ret = BIO_printf(bio, "test %s", string);
123    if (ret != 5 + kLengths[i]) {
124      fprintf(stderr, "BIO_printf failed\n");
125      return 0;
126    }
127    if (!BIO_mem_contents(bio, &contents, &len)) {
128      fprintf(stderr, "BIO_mem_contents failed\n");
129      return 0;
130    }
131    if (len != 5 + kLengths[i] ||
132        strncmp((const char *)contents, "test ", 5) != 0 ||
133        strncmp((const char *)contents + 5, string, kLengths[i]) != 0) {
134      fprintf(stderr, "Contents did not match: %.*s\n", (int)len, contents);
135      return 0;
136    }
137
138    if (!BIO_reset(bio)) {
139      fprintf(stderr, "BIO_reset failed\n");
140      return 0;
141    }
142  }
143
144  BIO_free(bio);
145  return 1;
146}
147
148int main(void) {
149  CRYPTO_library_init();
150  ERR_load_crypto_strings();
151
152  if (!test_socket_connect()) {
153    return 1;
154  }
155
156  if (!test_printf()) {
157    return 1;
158  }
159
160  printf("PASS\n");
161  return 0;
162}
163