spacepaste

  1.  
  2. /* Compile with: gcc -o simple_client2 simple_client2.c -std=gnu99 -lssl -lcrypto -ldl */
  3. #include <openssl/ssl.h>
  4. #include <openssl/bio.h>
  5. #include <openssl/err.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <sys/types.h>
  11. #include <errno.h>
  12. #include <assert.h>
  13. #include <sys/socket.h>
  14. #include <netinet/in.h>
  15. #include <netinet/tcp.h>
  16. #include <arpa/inet.h>
  17. #include <netdb.h>
  18. #include <sys/time.h>
  19. #include <string.h>
  20. #include <stdbool.h>
  21. // #include <iostream.h>
  22. // #include <iomanip.h>
  23. enum {
  24. FATAL = 0,
  25. ERROR,
  26. WARNING,
  27. INFO,
  28. DETAIL,
  29. DEBUG,
  30. TRACE
  31. };
  32. int _logLevel = DETAIL;
  33. #define LOG(level,msg) printf("LOG: %s\n", msg);
  34. #define LOG_ERROR(msg) printf("LOG ERR: %s\n", msg); //do { LOG(ERROR, "-E- " << __func__ << ' ' << msg << std::endl); } while(0)
  35. #define LOG_DEBUG(msg) printf("LOG DBG: %s\n", msg); //do { LOG(DEBUG, "-D- " << __func__ << ' ' << msg << '\n'); } while(0)
  36. #define LOG_INFO(msg) printf("LOG INF: %s\n", msg); //;do { LOG(INFO, "-I- " << __func__ << ' ' << msg << '\n'); } while(0)
  37. #define PERROR_AND_RETURN(rc) do { \
  38. LOG_ERROR(strerror(errno)); \
  39. return rc; \
  40. } while (0)
  41. struct addrinfo* get_addrinfo(const char* node, const char* service, bool tcp) {
  42. struct addrinfo hints;
  43. struct addrinfo* result = NULL;
  44. memset(&hints, 0, sizeof(struct addrinfo));
  45. hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
  46. hints.ai_socktype = tcp ? SOCK_STREAM : SOCK_DGRAM; /* Stream/Datagram socket */
  47. hints.ai_flags = 0;
  48. hints.ai_protocol = 0; /* Any protocol */
  49. int rc = 0;
  50. if (getaddrinfo(node, service, NULL/*&hints*/, &result) != 0) { LOG_ERROR(gai_strerror(rc)); return NULL; }
  51. return result;
  52. }
  53. /**
  54. *
  55. */
  56. int configure_socket(int fd, const struct addrinfo *ai, unsigned sndbuf, unsigned rcvbuf, bool blocking, bool nolinger, bool nodelay) {
  57. if (nolinger) {
  58. /* Set the socket for a non lingering, graceful close.
  59. * This will cause a final close of this socket not to wait until all
  60. * of the data sent on it has been received by the remote host.
  61. * The result is that the socket will be immediately released instead
  62. * of blocking in a TIME_WAIT state */
  63. int linger[] = {1, 0};
  64. if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  65. }
  66. // if (nodelay) {
  67. // int flag = 1;
  68. // if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  69. // }
  70. if (sndbuf > 0 && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  71. if (rcvbuf > 0 && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  72. // put socket to blocking/non-blocking mode
  73. int flags = -1;
  74. if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  75. if (blocking) flags &= ~O_NONBLOCK;
  76. else flags |= O_NONBLOCK;
  77. if (fcntl(fd, F_SETFL, flags) == -1) { LOG_ERROR(strerror(errno)); return -1; }
  78. return 0;
  79. }
  80. /**
  81. * returns tcp-connected socket
  82. */
  83. int get_tcp_connection(const char* node, const char* service) {
  84. struct addrinfo* ai = get_addrinfo(node, service, true /* tcp */);
  85. if (ai == NULL) return -1;
  86. const unsigned sndbuf = 1024*128;
  87. const unsigned rcvbuf = 1024*128;
  88. int fd = -1;
  89. for (struct addrinfo* rp = ai; rp != NULL; rp = rp->ai_next) {
  90. if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) { LOG_ERROR(strerror(errno)); fd = -1; break; }
  91. if (configure_socket(fd, rp, sndbuf, rcvbuf, true /* blocking */, true /* nolinger */, false /* nodelay */) != 0) { close(fd); fd = -1; break; }
  92. if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) break;
  93. close(fd); fd = -1;
  94. }
  95. freeaddrinfo(ai);
  96. return fd;
  97. }
  98. int main()
  99. {
  100. int p;
  101. const char* request;
  102. request = "POST /index HTTP/1.1\r\n"
  103. "Host: foo.com\r\n"
  104. "Content-Length: 5"
  105. "\r\n\r\n" "part3";
  106. char r[1024];
  107. /* Set up the library */
  108. SSL_library_init();
  109. ERR_load_BIO_strings();
  110. SSL_load_error_strings();
  111. OpenSSL_add_all_algorithms();
  112. /* Set up the SSL context */
  113. SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
  114. if (!ctx) {
  115. ERR_print_errors_fp(stderr);
  116. return 1;
  117. }
  118. SSL_CTX_set_session_id_context(ctx, "foobarbaz", 10);
  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 = -1;
  221. while (p < 0) {
  222. p = SSL_read(ssl, r, 1023);
  223. //if(p <= 0) break;
  224. printf("Received %d bytes\n", p);
  225. if (p >= 0) {
  226. r[p] = 0;
  227. printf("%s", r);
  228. }
  229. }
  230. // }
  231. exit(0);
  232. #if 0
  233. rc = SSL_shutdown(ssl);
  234. if(!rc){
  235. /* If we called SSL_shutdown() first then
  236. we always get return value of '0'. In
  237. this case, try again, but first send a
  238. TCP FIN to trigger the other side's
  239. close_notify*/
  240. shutdown(fd,1);
  241. rc = SSL_shutdown(ssl);
  242. }
  243. switch(rc){
  244. case 1:
  245. break; /* Success */
  246. case 0:
  247. case -1:
  248. default:
  249. LOG_ERROR("Shutdown failed");
  250. }
  251. /* Close the connection and free the context */
  252. SSL_CTX_free(ctx);
  253. // if (write(fd, request, strlen(request)) == -1) {
  254. // PERROR_AND_RETURN("write(fd, request, strlen(request))", 1);
  255. // }
  256. //
  257. // /* Read in the response */
  258. //
  259. // for(;;)
  260. // {
  261. // p = read(fd, r, 1023);
  262. // if(p <= 0) break;
  263. // r[p] = 0;
  264. // printf("%s", r);
  265. // }
  266. return 0;
  267. #endif
  268. }
  269.