git ssb

0+

cel / electrumc



Tree: fb6db7d0171f85ee76abb0f0ee5f1827c5eec31e

Files: fb6db7d0171f85ee76abb0f0ee5f1827c5eec31e / electrumc.c

3844 bytesRaw
1/* See LICENSE file for copyright and license details. */
2#include <err.h>
3#include <errno.h>
4#include <netdb.h>
5#include <netinet/in.h>
6#include <stdbool.h>
7#include <string.h>
8#include <sys/socket.h>
9#include <unistd.h>
10
11#include <openssl/ssl.h>
12
13static int tcp_connect(const char *host, const char *port) {
14 struct addrinfo hints;
15 struct addrinfo *result, *rp;
16 int s;
17 int fd;
18 int err;
19
20 memset(&hints, 0, sizeof(hints));
21 hints.ai_family = AF_UNSPEC;
22 hints.ai_protocol = IPPROTO_TCP;
23
24 s = getaddrinfo(host, port, &hints, &result);
25 if (s < 0) errx(1, "unable to resolve host: %s", gai_strerror(s));
26
27 for (rp = result; rp; rp = rp->ai_next) {
28 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
29 if (fd < 0) continue;
30 if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0) break;
31 err = errno;
32 close(fd);
33 errno = err;
34 }
35 if (rp == NULL) fd = -1;
36
37 freeaddrinfo(result);
38 return fd;
39}
40
41static int write_all(int fd, const void *buf, size_t count) {
42 ssize_t nbytes;
43 while (count > 0) {
44 nbytes = write(fd, buf, count);
45 if (nbytes < 0 && errno == EINTR) continue;
46 if (nbytes < 0) return -1;
47 buf += nbytes;
48 count -= nbytes;
49 }
50 return 0;
51}
52
53static void usage(int status) {
54 fputs("usage: electrumc <address> <port> <method> [<params>]\n",
55 status ? stderr : stdout);
56 exit(status);
57}
58
59static int read_response(int s, SSL *ssl, bool use_ssl) {
60 char buf[8192];
61 int len;
62
63 if (use_ssl) {
64 len = SSL_pending(ssl);
65 if (len < 0) errx(1, "ssl pending");
66 if (len == 0) len = 1;
67 else if (len > (int)sizeof(buf)) len = sizeof(buf);
68 len = SSL_read(ssl, buf, len);
69 if (len < 0) errx(1, "ssl read failed");
70 } else {
71 len = read(s, buf, sizeof(buf));
72 if (len == 0) return -1;
73 if (len < 0) err(1, "read");
74 }
75
76 len = fwrite(buf, 1, len, stdout);
77 if (len < 0) errx(1, "failed to print response");
78
79 if (buf[len-1] == '\n') return 1;
80 return 0;
81}
82
83int main(int argc, char *argv[]) {
84 int rc;
85 SSL *ssl;
86 SSL_CTX *ssl_ctx;
87 char *host, *port, *type, *method, *params;
88 int s;
89 bool use_ssl;
90
91 if (argc == 1) usage(0);
92 if (argc != 3 && argc != 4) usage(1);
93 host = argv[1];
94 method = argv[2];
95 params = argc == 3 ? NULL : argv[3];
96
97 type = strrchr(host, ':');
98 if (!type) errx(1, "address should be in format <host>:<port>:<type>");
99 *type++ = '\0';
100 if (!strcmp(type, "t")) use_ssl = false;
101 else if (!strcmp(type, "s")) use_ssl = true;
102 else errx(1, "address type must be 't' or 's', but found: '%s'", type);
103
104 port = strrchr(host, ':');
105 if (!port) errx(1, "address should be in format <host>:<port>:<type>");
106 *port++ = '\0';
107
108 if (!*host) errx(1, "address hostname missing");
109
110 if (use_ssl) {
111 ssl_ctx = SSL_CTX_new(TLS_client_method());
112 if (ssl_ctx == NULL) errx(1, "failed to create ssl context");
113 (void)SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
114
115 ssl = SSL_new(ssl_ctx);
116 if (ssl_ctx == NULL) errx(1, "failed to create ssl object");
117 }
118
119 s = tcp_connect(host, port);
120 if (s < 0) err(1, "failed to connect");
121
122 if (use_ssl) {
123 rc = SSL_set_fd(ssl, s);
124 if (rc < 0) errx(1, "failed to set ssl s");
125
126 rc = SSL_connect(ssl);
127 if (rc < 0) errx(1, "ssl_connect failed");
128 }
129
130 char buf[8192];
131 int len = snprintf(buf, sizeof(buf)-1, "{\"id\":0,\"method\":\"%s\"%s%s}\n",
132 method,
133 params ? ",\"params\":" : "",
134 params ? params : "");
135 if (len < 0 || len == (int)sizeof(buf)) errx(1, "request too long");
136
137 if (use_ssl) {
138 rc = SSL_write(ssl, buf, len);
139 if (rc < 0) errx(1, "ssl write failed");
140 } else {
141 len = write_all(s, buf, len);
142 if (len < 0) err(1, "write");
143 }
144
145 do rc = read_response(s, ssl, use_ssl);
146 while (rc == 0);
147 if (rc < 0 && errno == 0) errx(1, "incomplete response");
148 if (rc < 0) err(1, "read");
149
150 if (use_ssl) {
151 rc = SSL_shutdown(ssl);
152 if (rc < 0) errx(1, "ssl shutdown failed");
153 }
154 close(s);
155}
156

Built with git-ssb-web