channel-switch: use sys/ioctl.h instead of stropts.h
[rofl0r-MacGeiger.git] / netgui.c
blobad04f430312cc7a8c2fad1fbb168f92957b07ba0
1 #include "server.h"
2 #include "../lib/include/sblist.h"
3 #include "../lib/include/strlib.h"
4 #include <pthread.h>
6 static volatile int server_done = 0;
8 struct thread {
9 long long last_update;
10 pthread_t pt;
11 struct client client;
12 volatile int done;
15 static void dump_json_str(int fd, const char *key, const char *val) {
16 dprintf(fd, "\"%s\" : \"%s\", ", key, val);
18 static void dump_json_int(int fd, const char *key, int val) {
19 dprintf(fd, "\"%s\" : %d, ", key, val);
22 static void dump_wlan_json(int fd, size_t wlanid) {
23 struct wlaninfo wtmp, *w = &wtmp;
24 get_wlan(wlanid, w);
25 char buf[256+8];
26 assert(sizeof buf >= WPS_MAX_STR_LEN*4);
27 assert(sizeof buf >= sizeof(wlans[0].essid)*4);
28 dprintf(fd, "{");
29 dump_json_str(fd, "bssid", mac2str(w->mac, buf));
30 dump_json_str(fd, "essid", sanitize_string(w->essid, buf));
31 dump_json_int(fd, "channel", w->channel);
32 dump_json_int(fd, "rssi", w->last_rssi);
33 dump_json_str(fd, "enc", enctype_str(w->enctype));
34 dump_json_str(fd, "uptime", format_timestamp(w->timestamp, buf));
36 if(!w->wps) goto wps_done;
38 //if(w->wps->vendor[0]) drintf(fd, "\"vendor_oui\" : \"%02X%02X%02X\", ", vendor[0], vendor[1], vendor[2]);
39 if(w->wps->version) dump_json_int(fd, "wps_version", w->wps->version);
40 if(w->wps->state) dump_json_int(fd, "wps_state", w->wps->state);
41 if(w->wps->locked) dump_json_int(fd, "wps_locked", w->wps->locked);
43 if(w->wps->manufacturer[0]) dump_json_str(fd, "wps_manufacturer", sanitize_string(w->wps->manufacturer, buf));
44 if(w->wps->model_name[0]) dump_json_str(fd, "wps_model_name", sanitize_string(w->wps->model_name, buf));
45 if(w->wps->model_number[0]) dump_json_str(fd, "wps_model_number", sanitize_string(w->wps->model_number, buf));
46 if(w->wps->device_name[0]) dump_json_str(fd, "wps_device_name", sanitize_string(w->wps->device_name, buf));
47 if(w->wps->ssid[0]) dump_json_str(fd, "wps_ssid", sanitize_string(w->wps->ssid, buf));
48 if(w->wps->serial[0]) dump_json_str(fd, "wps_serial", sanitize_string(w->wps->serial, buf));
49 if(w->wps->os_version[0]) dump_json_str(fd, "wps_os_version", sanitize_string(w->wps->os_version, buf));
50 if(w->wps->uuid[0]) dump_json_str(fd, "wps_uuid", sanitize_string(w->wps->uuid, buf));
51 if(w->wps->selected_registrar[0]) dump_json_str(fd, "wps_selected_registrar", sanitize_string(w->wps->selected_registrar, buf));
52 if(w->wps->response_type[0]) dump_json_str(fd, "wps_response_type", sanitize_string(w->wps->response_type, buf));
53 if(w->wps->primary_device_type[0]) dump_json_str(fd, "wps_primary_device_type", sanitize_string(w->wps->primary_device_type, buf));
54 if(w->wps->config_methods[0]) dump_json_str(fd, "wps_config_methods", sanitize_string(w->wps->config_methods, buf));
55 if(w->wps->rf_bands[0]) dump_json_str(fd, "wps_rf_bands", sanitize_string(w->wps->rf_bands, buf));
57 wps_done:
58 dprintf(fd, "\"dummy\": 0}\n");
61 static void* clientthread(void *data) {
62 struct thread *t = data;
63 char buf[32];
64 ssize_t n;
65 size_t i, l;
66 while(!server_done) {
67 n = recv(t->client.fd, buf, sizeof buf, 0);
68 if(n <= 0) break;
69 if(!strcmp(buf, "LIST\n")) {
70 lock();
71 l = DYNA_COUNT(wlans);
72 unlock();
73 for(i=0; i<l; i++) {
74 lock();
75 long long ls = wlans[i].last_seen;
76 unlock();
77 if(ls > t->last_update)
78 dump_wlan_json(t->client.fd, i);
80 t->last_update = getutime64();
81 dprintf(t->client.fd, "END\n");
82 } else if (!strcmp(buf, "QUIT\n")) {
83 server_done = 1;
84 } else if(!strcmp(buf, "UNSELECT\n")) {
85 set_selection(0);
86 } else if((!strncmp(buf, "SELECT ", 7))
87 && strlen(buf) == 7 + 6*2 + 5 + 1
88 && buf[7 + 6*2 + 5] == '\n'
89 ) {
90 unsigned char mac[6], *m = mac;
91 char *p = buf + 7;
92 for(i=0;i<6;i++) {
93 *m = hexval(p);
94 p++;
95 *m = *m << 4 | hexval(p);
96 m++;
97 p+=2;
99 int newsel = -1;
100 lock();
101 l = DYNA_COUNT(wlans);
102 for(i=0;i<l; i++) {
103 if(!memcmp(wlans[i].mac, mac, 6)) {
104 newsel = i;
105 break;
108 unlock();
109 if(newsel > -1) {
110 selection = newsel;
111 set_selection(1);
115 return 0;
118 static void collect(sblist *threads) {
119 size_t i;
120 for(i=0;i<sblist_getsize(threads);) {
121 struct thread* thread = *((struct thread**)sblist_get(threads, i));
122 if(thread->done) {
123 pthread_join(thread->pt, 0);
124 sblist_delete(threads, i);
125 free(thread);
126 } else
127 i++;
131 struct netgui_config {
132 int port;
133 const char *listenaddr;
134 pthread_t thr;
137 static void* netgui_thread(void *args) {
138 struct netgui_config *cfg = args;
139 signal(SIGPIPE, SIG_IGN);
140 struct server s;
141 sblist *threads = sblist_new(sizeof (struct thread*), 8);
143 if(server_setup(&s, cfg->listenaddr, cfg->port)) {
144 perror("server_setup");
145 server_done = 1;
147 while(!server_done) {
148 collect(threads);
149 struct client c;
150 struct thread *curr = malloc(sizeof (struct thread));
151 if(!curr) goto oom;
152 curr->done = 0;
153 if(server_waitclient(&s, &c)) continue;
154 curr->client = c;
155 if(!sblist_add(threads, &curr)) {
156 close(curr->client.fd);
157 free(curr);
158 oom:
159 //dolog("rejecting connection due to OOM\n");
160 usleep(16); /* prevent 100% CPU usage in OOM situation */
161 continue;
163 pthread_attr_t *a = 0, attr;
164 if(pthread_attr_init(&attr) == 0) {
165 a = &attr;
166 pthread_attr_setstacksize(a, 64*1024);
168 if(pthread_create(&curr->pt, a, clientthread, curr) != 0) {
169 //dolog("pthread_create failed. OOM?\n");
171 if(a) pthread_attr_destroy(&attr);
173 size_t i;
174 for(i=0;i<sblist_getsize(threads);i++) {
175 struct thread* thread =
176 *((struct thread**)sblist_get(threads, i));
177 close(thread->client.fd);
179 collect(threads);
181 return 0;
184 void netgui_start(struct netgui_config *cfg, const char *listenaddr, int port) {
185 cfg->port = port;
186 cfg->listenaddr = listenaddr,
187 pthread_create(&cfg->thr, 0, netgui_thread, cfg);
190 void netgui_stop(struct netgui_config *cfg) {
191 server_done = 1;
193 /* connect to the listener so it returns from server_waitclient() */
194 int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
195 if(fd == -1) goto skip;
197 struct addrinfo *ainfo = 0;
198 const char *dst = "127.0.0.1";
199 if(strcmp(cfg->listenaddr, "0.0.0.0"))
200 dst = cfg->listenaddr;
201 if(resolve(dst, cfg->port, &ainfo)) goto skip;
203 connect(fd, ainfo->ai_addr, ainfo->ai_addrlen);
204 freeaddrinfo(ainfo);
206 skip:
207 pthread_join(cfg->thr, 0);