git ssb

0+

cel / electrumc



Tree: 0a1f41b812c27e9ddccaae10f72b6312f3dda913

Files: 0a1f41b812c27e9ddccaae10f72b6312f3dda913 / electrumc.c

3740 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 port = strchr(host, ':');
98 if (!port) errx(1, "address should be in format <host>:<port>:<type>");
99 *port++ = '\0';
100 type = strchr(port, ':');
101 if (!type) errx(1, "address type missing");
102 *type++ = '\0';
103
104 if (!strcmp(type, "t")) use_ssl = false;
105 else if (!strcmp(type, "s")) use_ssl = true;
106 else errx(1, "address type must be 't' or 's'");
107
108 if (use_ssl) {
109 ssl_ctx = SSL_CTX_new(TLS_client_method());
110 if (ssl_ctx == NULL) errx(1, "failed to create ssl context");
111 (void)SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
112
113 ssl = SSL_new(ssl_ctx);
114 if (ssl_ctx == NULL) errx(1, "failed to create ssl object");
115 }
116
117 s = tcp_connect(host, port);
118 if (s < 0) err(1, "failed to connect");
119
120 if (use_ssl) {
121 rc = SSL_set_fd(ssl, s);
122 if (rc < 0) errx(1, "failed to set ssl s");
123
124 rc = SSL_connect(ssl);
125 if (rc < 0) errx(1, "ssl_connect failed");
126 }
127
128 char buf[8192];
129 int len = snprintf(buf, sizeof(buf)-1, "{\"id\":0,\"method\":\"%s\"%s%s}\n",
130 method,
131 params ? ",\"params\":" : "",
132 params ? params : "");
133 if (len < 0 || len == (int)sizeof(buf)) errx(1, "request too long");
134
135 if (use_ssl) {
136 rc = SSL_write(ssl, buf, len);
137 if (rc < 0) errx(1, "ssl write failed");
138 } else {
139 len = write_all(s, buf, len);
140 if (len < 0) err(1, "write");
141 }
142
143 do rc = read_response(s, ssl, use_ssl);
144 while (rc == 0);
145 if (rc < 0 && errno == 0) errx(1, "incomplete response");
146 if (rc < 0) err(1, "read");
147
148 if (use_ssl) {
149 rc = SSL_shutdown(ssl);
150 if (rc < 0) errx(1, "ssl shutdown failed");
151 }
152 close(s);
153}
154

Built with git-ssb-web