/ api-example.c
api-example.c
  1  /*
  2   * Copyright 2011 Kano
  3   *
  4   * This program is free software; you can redistribute it and/or modify it
  5   * under the terms of the GNU General Public License as published by the Free
  6   * Software Foundation; either version 3 of the License, or (at your option)
  7   * any later version.  See COPYING for more details.
  8   */
  9  
 10  /* Compile:
 11   *   gcc api-example.c -Icompat/jansson-2.9/src -o cgminer-api
 12   */
 13  
 14  #include "config.h"
 15  
 16  #include <stdio.h>
 17  #include <stdlib.h>
 18  #include <string.h>
 19  #include <ctype.h>
 20  #include <unistd.h>
 21  #include <stdbool.h>
 22  #include <stdint.h>
 23  #include <sys/types.h>
 24  
 25  #include "compat.h"
 26  #include "util.h"
 27  
 28  #if defined(unix) || defined(__APPLE__)
 29  	#include <errno.h>
 30  	#include <sys/socket.h>
 31  	#include <netinet/in.h>
 32  	#include <arpa/inet.h>
 33  	#include <netdb.h>
 34  
 35  	#define SOCKETFAIL(a) ((a) < 0)
 36  	#define INVSOCK -1
 37  	#define CLOSESOCKET close
 38  
 39  	#define SOCKETINIT {}
 40  
 41  	#define SOCKERRMSG strerror(errno)
 42  #endif
 43  
 44  #ifdef WIN32
 45  	#include <winsock2.h>
 46  
 47  	#define SOCKETTYPE SOCKET
 48  	#define SOCKETFAIL(a) ((a) == SOCKET_ERROR)
 49  	#define INVSOCK INVALID_SOCKET
 50  	#define CLOSESOCKET closesocket
 51  
 52  	static char WSAbuf[1024];
 53  
 54  	struct WSAERRORS {
 55  		int id;
 56  		char *code;
 57  	} WSAErrors[] = {
 58  		{ 0,			"No error" },
 59  		{ WSAEINTR,		"Interrupted system call" },
 60  		{ WSAEBADF,		"Bad file number" },
 61  		{ WSAEACCES,		"Permission denied" },
 62  		{ WSAEFAULT,		"Bad address" },
 63  		{ WSAEINVAL,		"Invalid argument" },
 64  		{ WSAEMFILE,		"Too many open sockets" },
 65  		{ WSAEWOULDBLOCK,	"Operation would block" },
 66  		{ WSAEINPROGRESS,	"Operation now in progress" },
 67  		{ WSAEALREADY,		"Operation already in progress" },
 68  		{ WSAENOTSOCK,		"Socket operation on non-socket" },
 69  		{ WSAEDESTADDRREQ,	"Destination address required" },
 70  		{ WSAEMSGSIZE,		"Message too long" },
 71  		{ WSAEPROTOTYPE,	"Protocol wrong type for socket" },
 72  		{ WSAENOPROTOOPT,	"Bad protocol option" },
 73  		{ WSAEPROTONOSUPPORT,	"Protocol not supported" },
 74  		{ WSAESOCKTNOSUPPORT,	"Socket type not supported" },
 75  		{ WSAEOPNOTSUPP,	"Operation not supported on socket" },
 76  		{ WSAEPFNOSUPPORT,	"Protocol family not supported" },
 77  		{ WSAEAFNOSUPPORT,	"Address family not supported" },
 78  		{ WSAEADDRINUSE,	"Address already in use" },
 79  		{ WSAEADDRNOTAVAIL,	"Can't assign requested address" },
 80  		{ WSAENETDOWN,		"Network is down" },
 81  		{ WSAENETUNREACH,	"Network is unreachable" },
 82  		{ WSAENETRESET,		"Net connection reset" },
 83  		{ WSAECONNABORTED,	"Software caused connection abort" },
 84  		{ WSAECONNRESET,	"Connection reset by peer" },
 85  		{ WSAENOBUFS,		"No buffer space available" },
 86  		{ WSAEISCONN,		"Socket is already connected" },
 87  		{ WSAENOTCONN,		"Socket is not connected" },
 88  		{ WSAESHUTDOWN,		"Can't send after socket shutdown" },
 89  		{ WSAETOOMANYREFS,	"Too many references, can't splice" },
 90  		{ WSAETIMEDOUT,		"Connection timed out" },
 91  		{ WSAECONNREFUSED,	"Connection refused" },
 92  		{ WSAELOOP,		"Too many levels of symbolic links" },
 93  		{ WSAENAMETOOLONG,	"File name too long" },
 94  		{ WSAEHOSTDOWN,		"Host is down" },
 95  		{ WSAEHOSTUNREACH,	"No route to host" },
 96  		{ WSAENOTEMPTY,		"Directory not empty" },
 97  		{ WSAEPROCLIM,		"Too many processes" },
 98  		{ WSAEUSERS,		"Too many users" },
 99  		{ WSAEDQUOT,		"Disc quota exceeded" },
100  		{ WSAESTALE,		"Stale NFS file handle" },
101  		{ WSAEREMOTE,		"Too many levels of remote in path" },
102  		{ WSASYSNOTREADY,	"Network system is unavailable" },
103  		{ WSAVERNOTSUPPORTED,	"Winsock version out of range" },
104  		{ WSANOTINITIALISED,	"WSAStartup not yet called" },
105  		{ WSAEDISCON,		"Graceful shutdown in progress" },
106  		{ WSAHOST_NOT_FOUND,	"Host not found" },
107  		{ WSANO_DATA,		"No host data of that type was found" },
108  		{ -1,			"Unknown error code" }
109  	};
110  
111  	static char *WSAErrorMsg()
112  	{
113  		char *msg;
114  		int i;
115  		int id = WSAGetLastError();
116  
117  		/* Assume none of them are actually -1 */
118  		for (i = 0; WSAErrors[i].id != -1; i++)
119  			if (WSAErrors[i].id == id)
120  				break;
121  
122  		sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code);
123  
124  		return &(WSAbuf[0]);
125  	}
126  
127  	#define SOCKERRMSG WSAErrorMsg()
128  
129  	static WSADATA WSA_Data;
130  
131  	#define SOCKETINIT	int wsa; \
132  				if (wsa = WSAStartup(0x0202, &WSA_Data)) { \
133  					printf("Socket startup failed: %d\n", wsa); \
134  					return 1; \
135  				}
136  
137  	#ifndef SHUT_RDWR
138  	#define SHUT_RDWR SD_BOTH
139  	#endif
140  #endif
141  
142  static const char SEPARATOR = '|';
143  static const char COMMA = ',';
144  static const char EQ = '=';
145  static int ONLY;
146  
147  void display(char *buf)
148  {
149  	char *nextobj, *item, *nextitem, *eq;
150  	int itemcount;
151  
152  	while (buf != NULL) {
153  		nextobj = strchr(buf, SEPARATOR);
154  		if (nextobj != NULL)
155  			*(nextobj++) = '\0';
156  
157  		if (*buf) {
158  			item = buf;
159  			itemcount = 0;
160  			while (item != NULL) {
161  				nextitem = strchr(item, COMMA);
162  				if (nextitem != NULL)
163  					*(nextitem++) = '\0';
164  
165  				if (*item) {
166  					eq = strchr(item, EQ);
167  					if (eq != NULL)
168  						*(eq++) = '\0';
169  
170  					if (itemcount == 0)
171  						printf("[%s%s] =>\n(\n", item, (eq != NULL && isdigit(*eq)) ? eq : "");
172  
173  					if (eq != NULL)
174  						printf("   [%s] => %s\n", item, eq);
175  					else
176  						printf("   [%d] => %s\n", itemcount, item);
177  				}
178  
179  				item = nextitem;
180  				itemcount++;
181  			}
182  			if (itemcount > 0)
183  				puts(")");
184  		}
185  
186  		buf = nextobj;
187  	}
188  }
189  
190  #define SOCKSIZ 65535
191  
192  int callapi(char *command, char *host, short int port)
193  {
194  	struct hostent *ip;
195  	struct sockaddr_in serv;
196  	SOCKETTYPE sock;
197  	int ret = 0;
198  	int n;
199  	char *buf = NULL;
200  	size_t len, p;
201  
202  	SOCKETINIT;
203  
204  	ip = gethostbyname(host);
205  	if (!ip) {
206  		printf("Couldn't get hostname: '%s'\n", host);
207  		return 1;
208  	}
209  
210  	sock = socket(AF_INET, SOCK_STREAM, 0);
211  	if (sock == INVSOCK) {
212  		printf("Socket initialisation failed: %s\n", SOCKERRMSG);
213  		return 1;
214  	}
215  
216  	memset(&serv, 0, sizeof(serv));
217  	serv.sin_family = AF_INET;
218  	serv.sin_addr = *((struct in_addr *)ip->h_addr);
219  	serv.sin_port = htons(port);
220  
221  	if (SOCKETFAIL(connect(sock, (struct sockaddr *)&serv, sizeof(struct sockaddr)))) {
222  		printf("Socket connect failed: %s\n", SOCKERRMSG);
223  		return 1;
224  	}
225  
226  	n = send(sock, command, strlen(command), 0);
227  	if (SOCKETFAIL(n)) {
228  		printf("Send failed: %s\n", SOCKERRMSG);
229  		ret = 1;
230  	}
231  	else {
232  		len = SOCKSIZ;
233  		buf = malloc(len+1);
234  		if (!buf) {
235  			printf("Err: OOM (%d)\n", (int)(len+1));
236  			return 1;
237  		}
238  		p = 0;
239  		while (42) {
240  			if ((len - p) < 1) {
241  				len += SOCKSIZ;
242  				buf = realloc(buf, len+1);
243  				if (!buf) {
244  					printf("Err: OOM (%d)\n", (int)(len+1));
245  					return 1;
246  				}
247  			}
248  
249  			n = recv(sock, &buf[p], len - p , 0);
250  
251  			if (SOCKETFAIL(n)) {
252  				printf("Recv failed: %s\n", SOCKERRMSG);
253  				ret = 1;
254  				break;
255  			}
256  
257  			if (n == 0)
258  				break;
259  
260  			p += n;
261  		}
262  		buf[p] = '\0';
263  
264  		if (ONLY)
265  			printf("%s\n", buf);
266  		else {
267  			printf("Reply was '%s'\n", buf);
268  			display(buf);
269  		}
270  	}
271  
272  	CLOSESOCKET(sock);
273  
274  	return ret;
275  }
276  
277  static char *trim(char *str)
278  {
279  	char *ptr;
280  
281  	while (isspace(*str))
282  		str++;
283  
284  	ptr = strchr(str, '\0');
285  	while (ptr-- > str) {
286  		if (isspace(*ptr))
287  			*ptr = '\0';
288  	}
289  
290  	return str;
291  }
292  
293  int main(int argc, char *argv[])
294  {
295  	char *command = "summary";
296  	char *host = "127.0.0.1";
297  	short int port = 4028;
298  	char *ptr;
299  	int i = 1;
300  
301  	if (argc > 1)
302  		if (strcmp(argv[1], "-?") == 0
303  		||  strcmp(argv[1], "-h") == 0
304  		||  strcmp(argv[1], "--help") == 0) {
305  			fprintf(stderr, "usAge: %s [command [ip/host [port]]]\n", argv[0]);
306  			return 1;
307  		}
308  
309  	if (argc > 1)
310  		if (strcmp(argv[1], "-o") == 0) {
311  			ONLY = 1;
312  			i = 2;
313  		}
314  
315  	if (argc > i) {
316  		ptr = trim(argv[i++]);
317  		if (strlen(ptr) > 0)
318  			command = ptr;
319  	}
320  
321  	if (argc > i) {
322  		ptr = trim(argv[i++]);
323  		if (strlen(ptr) > 0)
324  			host = ptr;
325  	}
326  
327  	if (argc > i) {
328  		ptr = trim(argv[i]);
329  		if (strlen(ptr) > 0)
330  			port = atoi(ptr);
331  	}
332  
333  	return callapi(command, host, port);
334  }