spacepaste

  1.  
  2. Compile with: gcc -o simple_client2 simple_client2.c -std=gnu99 -lssl -lcrypto -ldl
  3. I'm using OpenSSL 1.0.2g
  4. #include <openssl/ssl.h>
  5. #include <openssl/bio.h>
  6. #include <openssl/err.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <fcntl.h>
  11. #include <sys/types.h>
  12. #include <errno.h>
  13. #include <assert.h>
  14. #include <sys/socket.h>
  15. #include <netinet/in.h>
  16. #include <netinet/tcp.h>
  17. #include <arpa/inet.h>
  18. #include <netdb.h>
  19. #include <sys/time.h>
  20. #include <string.h>
  21. #include <stdbool.h>
  22. // #include <iostream.h>
  23. // #include <iomanip.h>
  24. enum {
  25. FATAL = 0,
  26. ERROR,
  27. WARNING,
  28. INFO,
  29. DETAIL,
  30. DEBUG,
  31. TRACE
  32. };
  33. int _logLevel = DETAIL;
  34. #define LOG(level,msg) printf("LOG: %s\n", msg);
  35. #define LOG_ERROR(msg) printf("LOG ERR: %s\n", msg); //do { LOG(ERROR, "-E- " << __func__ << ' ' << msg << std::endl); } while(0)
  36. #define LOG_DEBUG(msg) printf("LOG DBG: %s\n", msg); //do { LOG(DEBUG, "-D- " << __func__ << ' ' << msg << '\n'); } while(0)
  37. #define LOG_INFO(msg) printf("LOG INF: %s\n", msg); //;do { LOG(INFO, "-I- " << __func__ << ' ' << msg << '\n'); } while(0)
  38. #define PERROR_AND_RETURN(rc) do { \
  39. LOG_ERROR(strerror(errno)); \
  40. return rc; \
  41. } while (0)
  42. struct addrinfo* get_addrinfo(const char* node, const char* service, bool tcp) {
  43. struct addrinfo hints;
  44. struct addrinfo* result = NULL;
  45. memset(&hints, 0, sizeof(struct addrinfo));
  46. hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
  47. hints.ai_socktype = tcp ? SOCK_STREAM : SOCK_DGRAM; /* Stream/Datagram socket */
  48. hints.ai_flags = 0;
  49. hints.ai_protocol = 0; /* Any protocol */
  50. int rc = 0;
  51. if (getaddrinfo(node, service, NULL/*&hints*/, &result) != 0) { LOG_ERROR(gai_strerror(rc)); return NULL; }
  52. return result;
  53. }
  54. /**
  55. *
  56. */
  57. int configure_socket(int fd, const struct addrinfo *ai, unsigned sndbuf, unsigned rcvbuf, bool blocking, bool nolinger, bool nodelay) {
  58. if (nolinger) {
  59. /* Set the socket for a non lingering, graceful close.
  60. * This will cause a final close of this socket not to wait until all
  61. * of the data sent on it has been received by the remote host.
  62. * The result is that the socket will be immediately released instead
  63. * of blocking in a TIME_WAIT state */
  64. int linger[] = {1, 0};
  65. if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  66. }
  67. // if (nodelay) {
  68. // int flag = 1;
  69. // if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  70. // }
  71. if (sndbuf > 0 && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  72. if (rcvbuf > 0 && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  73. // put socket to blocking/non-blocking mode
  74. int flags = -1;
  75. if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  76. if (blocking) flags &= ~O_NONBLOCK;
  77. else flags |= O_NONBLOCK;
  78. if (fcntl(fd, F_SETFL, flags) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  79. return 0;
  80. }
  81. /**
  82. * returns tcp-connected socket
  83. */
  84. int get_tcp_connection(const char* node, const char* service) {
  85. struct addrinfo* ai = get_addrinfo(node, service, true /* tcp */);
  86. if (ai == NULL) return -1;
  87. const unsigned sndbuf = 1024*128;
  88. const unsigned rcvbuf = 1024*128;
  89. int fd = -1;
  90. for (struct addrinfo* rp = ai; rp != NULL; rp = rp->ai_next) {
  91. if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) { LOG_ERROR(strerror(errno)); fd = -1; break; }
  92. if (configure_socket(fd, rp, sndbuf, rcvbuf, true /* blocking */, true /* nolinger */, false /* nodelay */) != 0) { close(fd); fd = -1; break; }
  93. if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) break;
  94. close(fd); fd = -1;
  95. }
  96. freeaddrinfo(ai);
  97. return fd;
  98. }
  99. int main()
  100. {
  101. int p;
  102. const char* request;
  103. request = "POST /index HTTP/1.1\r\n"
  104. "Host: foo.com\r\n"
  105. "Content-Length: 5"
  106. "\r\n\r\n" "part3";
  107. char r[1024];
  108. /* Set up the library */
  109. SSL_library_init();
  110. ERR_load_BIO_strings();
  111. SSL_load_error_strings();
  112. OpenSSL_add_all_algorithms();
  113. /* Set up the SSL context */
  114. SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
  115. if (!ctx) {
  116. ERR_print_errors_fp(stderr);
  117. return 1;
  118. }
  119. /* Load the trust store */
  120. #if 0
  121. if(! SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs"))
  122. {
  123. fprintf(stderr, "Error loading trust store\n");
  124. ERR_print_errors_fp(stderr);
  125. SSL_CTX_free(ctx);
  126. return 0;
  127. }
  128. #endif
  129. /* Setup the connection */
  130. int fd = get_tcp_connection("127.0.0.1", "5555");
  131. // int fd = my_connect("127.0.0.1", 80);
  132. if (fd == -1) {
  133. LOG_ERROR(strerror(errno));
  134. return 1;
  135. }
  136. SSL* ssl = SSL_new(ctx); assert(ssl);
  137. if (!SSL_set_fd(ssl, fd)) {
  138. LOG_ERROR("SSL_set_fd(ssl, fd)");
  139. return 1;
  140. }
  141. SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
  142. int rc = SSL_get_error(ssl, SSL_connect(ssl));
  143. if (rc != SSL_ERROR_NONE) {
  144. LOG_ERROR(ERR_error_string(rc, NULL));
  145. while ((rc = ERR_get_error()) != 0) {
  146. LOG_ERROR(ERR_error_string(rc, NULL));
  147. }
  148. return 1;
  149. }
  150. /* Check the certificate */
  151. #if 0
  152. rc = SSL_get_verify_result(ssl);
  153. if(rc != X509_V_OK)
  154. {
  155. if (rc == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || rc == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) {
  156. fprintf(stderr, "self signed certificate\n");
  157. }
  158. else {
  159. fprintf(stderr, "Certificate verification error: %ld\n", SSL_get_verify_result(ssl));
  160. SSL_CTX_free(ctx);
  161. return 0;
  162. }
  163. }
  164. #endif
  165. /* Send the request */
  166. request = "POST /index HTTP/1.1\r\n"
  167. "Host: foo.com\r\n"
  168. "Content-Length: 5"
  169. "\r\n\r\n" "part1";
  170. if (SSL_write(ssl, request, strlen(request)) == -1) {
  171. PERROR_AND_RETURN(1);
  172. }
  173. LOG_INFO("Data sent [");
  174. LOG_INFO(request);
  175. LOG_INFO("]");
  176. /* Read in the response */
  177. // for(;;)
  178. // {
  179. p = SSL_read(ssl, r, 1023);
  180. //if(p <= 0) break;
  181. r[p] = 0;
  182. printf("%s", r);
  183. // }
  184. /* Send the request */
  185. request = "POST /index HTTP/1.1\r\n"
  186. "Host: foo.com\r\n"
  187. "Content-Length: 5"
  188. "\r\n\r\n" "part2";
  189. if (SSL_write(ssl, request, strlen(request)) == -1) {
  190. PERROR_AND_RETURN(1);
  191. }
  192. LOG_INFO("Data sent [");
  193. LOG_INFO(request);
  194. LOG_INFO("]");
  195. /* Read in the response */
  196. // for(;;)
  197. // {
  198. p = SSL_read(ssl, r, 1023);
  199. //if(p <= 0) break;
  200. r[p] = 0;
  201. printf("%s", r);
  202. // }
  203. SSL_renegotiate_abbreviated(ssl);
  204. while(!SSL_do_handshake(ssl));
  205. SSL_heartbeat(ssl);
  206. /* Send the request */
  207. request = "POST /index HTTP/1.1\r\n"
  208. "Host: foo.com\r\n"
  209. "Content-Length: 5"
  210. "\r\n\r\n" "part3";
  211. if (SSL_write(ssl, request, strlen(request)) == -1) {
  212. PERROR_AND_RETURN(1);
  213. }
  214. LOG_INFO("Data sent [");
  215. LOG_INFO(request);
  216. LOG_INFO("]");
  217. /* Read in the response */
  218. // for(;;)
  219. // {
  220. p = SSL_read(ssl, r, 1023);
  221. //if(p <= 0) break;
  222. printf("Received %d bytes\n", p);
  223. if (p >= 0) {
  224. r[p] = 0;
  225. printf("%s", r);
  226. }
  227. // }
  228. exit(0);
  229. #if 0
  230. rc = SSL_shutdown(ssl);
  231. if(!rc){
  232. /* If we called SSL_shutdown() first then
  233. we always get return value of '0'. In
  234. this case, try again, but first send a
  235. TCP FIN to trigger the other side's
  236. close_notify*/
  237. shutdown(fd,1);
  238. rc = SSL_shutdown(ssl);
  239. }
  240. switch(rc){
  241. case 1:
  242. break; /* Success */
  243. case 0:
  244. case -1:
  245. default:
  246. LOG_ERROR("Shutdown failed");
  247. }
  248. /* Close the connection and free the context */
  249. SSL_CTX_free(ctx);
  250. // if (write(fd, request, strlen(request)) == -1) {
  251. // PERROR_AND_RETURN("write(fd, request, strlen(request))", 1);
  252. // }
  253. //
  254. // /* Read in the response */
  255. //
  256. // for(;;)
  257. // {
  258. // p = read(fd, r, 1023);
  259. // if(p <= 0) break;
  260. // r[p] = 0;
  261. // printf("%s", r);
  262. // }
  263. return 0;
  264. #endif
  265. }
  266.