1 //
2 // anyRemote
3 // a wi-fi or bluetooth remote for your PC.
4 //
5 // Copyright (C) 2006-2018 Mikhail Fedotov <anyremote@mail.ru>
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21
22 #include <errno.h>
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "atsend.h"
29 #include "btio.h"
30 #include "common.h"
31 #include "conf.h"
32 #include "dispatcher.h"
33 #include "executor.h"
34 #include "gen_ar.h"
35 #include "peer.h"
36 #include "pr_btspp.h"
37 #include "pr_frontend.h"
38 #include "pr_l2cap.h"
39 #include "pr_rfcomm.h"
40 #include "pr_serial.h"
41 #include "pr_socket.h"
42 #include "pr_stdin.h"
43 #include "pr_web.h"
44 #include "state.h"
45 #include "str.h"
46 #include "utils.h"
47
48 extern char tmp[MAXMAXLEN];
49
50 // executor.c
51 extern void customizePeer(int id, int szX, int szY, int coverSz);
52
53 static int _peerCounter = 1;
54 static SingleList * _connections = NULL;
55
56 static int peerWrite (ConnectInfo* peer, const dMessage* msg);
57 static int peerWriteBytes(ConnectInfo* peer, const char* command);
58 static void writeIViewerHeartbeat(int fd);
59 static void writeBemusedHeartbeat(int fd);
60
61
allocPeer(boolean_t allocCache)62 static ConnectInfo* allocPeer(boolean_t allocCache)
63 {
64 ConnectInfo* peer = (ConnectInfo*) malloc(sizeof(ConnectInfo));
65
66 peer->id = _peerCounter;
67 _peerCounter++;
68 peer->mode = SERVER_MAX;
69 peer->state = PEER_DISCONNECTED;
70 peer->port = -1;
71 peer->connectionData = NULL; // specific to connection
72 peer->portStr = NULL;
73
74 if (allocCache) {
75 peer->cache = (DCache*) malloc(sizeof(DCache));
76 int i=0;
77 for (; i<ID_SET_MAX; i++) {
78 peer->cache->lastValues [i] = NULL;
79 peer->cache->lastValuesSize[i] = -1;
80 }
81 } else {
82 peer->cache = NULL;
83 }
84
85 return peer;
86 }
87
freeCachedData(ConnectInfo * peer)88 static void freeCachedData(ConnectInfo* peer)
89 {
90 INFO2("[DS]: freeCachedData() peer %d", peer->id);
91 DCache* cache = peer->cache;
92 if (cache) {
93 int i = 0;
94 for (; i<ID_SET_MAX; i++) {
95 if (cache->lastValues[i]) {
96 free(cache->lastValues[i]);
97 cache->lastValues[i] = NULL;
98 }
99 }
100 }
101 }
102
freePeer(void * data)103 static void freePeer(void* data)
104 {
105 ConnectInfo* peer = (ConnectInfo* ) data;
106 INFO2("[DS]: freePeer() %d", peer->id);
107 if (peer->connectionData) {
108 free(peer->connectionData);
109 }
110 freeCachedData(peer);
111 free(peer);
112 }
113
114 // do not take into account connection-less peers (HTML + XML)
countConnections()115 static int countConnections()
116 {
117 int cnum = 0;
118 SingleList* list = _connections;
119 //INFO2("[DS]: countConnections() enter %d", listSingleLength(list));
120
121 while (list) {
122 ConnectInfo* peer = (ConnectInfo*) list->data;
123 if (peer->state == PEER_CONNECTED && peer->mode != FRONT_END) {
124 cnum++;
125 }
126 list = listSingleNext(list);
127 }
128 return cnum;
129 }
130
131 // do not take into account connection-less peers (HTML + XML)
countOtherConnections(ConnectInfo * peer)132 static int countOtherConnections(ConnectInfo* peer)
133 {
134 int cnum = 0;
135 SingleList* list = _connections;
136
137 while (list) {
138 ConnectInfo* otherPeer = (ConnectInfo*) list->data;
139 if (otherPeer->state == PEER_CONNECTED && otherPeer->mode != FRONT_END && otherPeer != peer) {
140 cnum++;
141 } else if (peer->mode == SERVER_WEB || peer->mode == SERVER_CMXML) {
142 cnum++;
143 }
144 list = listSingleNext(list);
145 }
146 return cnum;
147 }
148
dummyOpen(ConnectInfo * connInfo)149 static int dummyOpen(ConnectInfo* connInfo)
150 {
151 DEBUG2("[DS]: dummyOpen");
152 return EXIT_OK;
153 }
154
dummyFD(ConnectInfo * connInfo)155 static int dummyFD(ConnectInfo* connInfo)
156 {
157 return -1;
158 }
159
setupNope(ConnectInfo * p)160 static int setupNope(ConnectInfo* p)
161 {
162 return 1;
163 }
164
acceptNope(ConnectInfo * p)165 static int acceptNope(ConnectInfo* p)
166 {
167 switch (p->mode) {
168 case SERVER_WEB:
169 logger(L_INF, "[DS]: Built-in web server: init OK");
170 break;
171 case SERVER_CMXML:
172 logger(L_INF, "[DS]: Built-in XML server: init OK");
173 break;
174 case CLIENT_ILIRC:
175 case CLIENT_NOAT:
176 case SERVER_STDIN:
177 logger(L_INF, "[DS]: Unix client: init OK");
178 break;
179 }
180 return 1;
181 }
182
183 static struct {
184 int id;
185 int (*descriptor) (ConnectInfo* p);
186 int (*openConnection) (ConnectInfo* p);
187 int (*setupPre) (ConnectInfo* p);
188 int (*listenConnection) (ConnectInfo* p);
189 int (*acceptConnection) (ConnectInfo* p);
190 int (*setupPost) (ConnectInfo* p); // unused ?
191 int (*writeConnection) (ConnectInfo* p, const dMessage* msg);
192 int (*writeBytesConnection) (ConnectInfo* p, const char* value);
193 void (*resetConnection) (ConnectInfo* p);
194 void (*closeConnection) (ConnectInfo* p, int final);
195 } _peerHandlers[] = {
196
197 // type get FD open setup_pre listen accept setup_post write write bytes reset close
198 // (EXIT_OK/ (1/-1) (1/-1) (1/-1) (EXIT_OK/ (1/-1) (EXIT_OK/ (void) (void) (void)
199 // NOK) NOK) NOK)
200 {CLIENT_RFCOMM, rfcommFD, rfcommConnect,rfcommSetup, setupNope, acceptNope, setupNope, peerWrite, NULL, rfcommReset, rfcommClose},
201 {CLIENT_AT, serialFD, serialOpen, serialSetup, setupNope, acceptNope, setupNope, peerWrite, NULL, serialReset, serialClose},
202 {SERVER_TCP, socketFD, socketOpen, setupNope, socketListen, socketAccept, setupNope, socketWrite, peerWriteBytes, socketReset, socketClose},
203 {SERVER_BT, btsppFD, btsppOpen, setupNope, setupNope, btsppAccept, setupNope, peerWrite, peerWriteBytes, btsppReset, btsppClose },
204 /*call btsppListen from btsppOpen */
205 {CLIENT_ILIRC, uxsFD, uxsOpen, setupNope, setupNope, acceptNope, setupNope, NULL, NULL, uxsReset, uxsClose },
206 {CLIENT_NOAT, serialFD, serialOpen, setupNope, setupNope, acceptNope, setupNope, peerWrite, NULL, serialReset, serialClose},
207 {SERVER_STDIN, dummyFD, stdinOpen, setupNope, setupNope, acceptNope, setupNope, NULL, NULL, stdinReset, stdinClose },
208 {SERVER_WEB, webFD, openWeb, setupNope, listenWeb, acceptWeb, setupNope, writeWeb, NULL, webReset, webClose },
209 {SERVER_CMXML, webFD, openWeb, setupNope, listenWeb, acceptWeb, setupNope, writeWeb, NULL, webReset, webClose },
210 #ifdef USE_L2CAP
211 {SERVER_L2CAP, l2capFD, l2capOpen, setupNope, l2capSetup, l2capAccept, setupNope, peerWrite, peerWriteBytes, l2capReset, l2capClose },
212 #endif
213 {SERVER_UX , socketFD, dummyOpen, setupNope, socketListen, socketAccept, setupNope, peerWrite, peerWriteBytes, socketReset, socketClose}, // not used
214 {FRONT_END , feFD, feOpen, setupNope, setupNope, acceptNope, setupNope, NULL, NULL, feReset, feClose }
215 };
216
freePeers()217 void freePeers()
218 {
219 INFO2("[DS]: freePeers() start");
220 listSingleFullFree(_connections, freePeer);
221 _connections = NULL;
222
223 freeState();
224
225 INFO2("[DS]: freePeers() end");
226 }
227
addTcpPeer(ConnectInfo * peer,char * strPort)228 static int addTcpPeer(ConnectInfo* peer, char *strPort)
229 {
230 // check is it port or unix socket
231 char * ch = strPort;
232 int isPort = 1;
233 while (*ch != '\0') {
234 if (isdigit(*ch)) {
235 ch++;
236 } else {
237 isPort = 0;
238 break;
239 }
240 }
241
242 if (isPort) {
243
244 peer->mode = SERVER_TCP;
245 peer->port = atoi(strPort);
246
247 if (peer->port <= 0) {
248 printf("ERROR: Improper port to use %d!\n", peer->port);
249 ERROR2("[DS]: Improper port %d to use", peer->port);
250 return EXIT_ABORT;
251 }
252
253 DEBUG2("[DS]: Peer %d: TCP Server mode, port %d", peer->id, peer->port);
254
255 } else {
256
257 /*sprintf(tmp, "Unix socket Server mode. Use socket %s\n", strPort);
258 logger(L_DBG, tmp);
259
260 if ((ret = openSocketPort(SERVER_UX, -1, strPort)) < 0) {
261 return -1;
262 }
263 peer->mode = SERVER_UX;
264 peer->portStr = stringNew(strPort);
265 */
266 printf("ERROR: incorrect port\n");
267 return EXIT_ABORT;
268
269 }
270 return EXIT_OK;
271 }
272
273 //
274 // fill ConnectInfo structure, return EXIT_ABORT in unsuccessful
275 //
addPeer(char * portIn)276 static int addPeer(char * portIn)
277 {
278
279 if (portIn == NULL) {
280 return EXIT_ABORT;
281 }
282 INFO2("[DS]: addPeer() %s", portIn);
283
284 char* strPort;
285
286 // device should be in format:
287
288 // deprecated
289 // 1. (AT mode) /dev/something used with AT mode commands
290
291 // 1. (AT mode) rfcomm:00:12:EF:32:21:1A:xx (xx is integer from 1 to 32)
292 // 2. (Server mode) socket:NNNN or used with java client
293 // socket:/path/to/socket used with java client (SERVER_UX, not used)
294 // 3. (Server mode) bluetooth:NN or bluetooth (port will be = DEFAULT_BT_CHANNEL) used with java client
295 // 4. (Server mode) web:NNNN built-in web server
296 // 5. (Server mode) cmxml:NNNN XML services interface
297 // 6. local:/some/path used with java client, like 1, but no AT commands
298 // 7. ilirc:/dev/something like 1, but no AT commands
299 // 8. stdio used with java client, like 1, but no AT commands
300 // 9. avahi skipped here
301
302
303 ConnectInfo* peer = allocPeer(BOOL_YES);
304
305 if ((strPort = strstr(portIn, INET_SOCKET)) != NULL) {
306
307 strPort += strlen(INET_SOCKET);
308
309 if (addTcpPeer(peer, strPort) == EXIT_ABORT) {
310 free(peer);
311 return EXIT_ABORT;
312 }
313
314 } else if ((strPort = strstr(portIn, PEER_TCP)) != NULL) {
315
316 strPort += strlen(PEER_TCP);
317
318 if (addTcpPeer(peer, strPort) == EXIT_ABORT) {
319 free(peer);
320 return EXIT_ABORT;
321 }
322
323 } else if ((strPort = strstr(portIn, ILIRC_SOCKET)) != NULL) {
324
325 strPort += strlen(ILIRC_SOCKET);
326
327 peer->mode = CLIENT_ILIRC;
328 peer->portStr = stringNew(strPort);
329
330 DEBUG2("[DS]: Peer %d: Unix socket client mode, socket %s", peer->id, peer->portStr->str);
331
332 } else if ((strPort = strstr(portIn, BT_SOCKET)) != NULL) {
333
334 strPort += strlen(BT_SOCKET);
335
336 peer->mode = SERVER_BT;
337 if (strstr(strPort, ":") == NULL) { // just "bluetooth
338 peer->port = DEFAULT_BT_CHANNEL;
339 } else {
340 strPort++;
341 peer->port = atoi(strPort);
342 }
343 DEBUG2("[DS]: Peer %d: Bluetooth Server mode, channel %d", peer->id, peer->port);
344
345 } else if ((strPort = strstr(portIn, L2CAP_SOCKET)) != NULL) {
346
347 #ifdef USE_L2CAP
348 strPort += strlen(L2CAP_SOCKET);
349
350 peer->mode = SERVER_L2CAP;
351 if (strstr(strPort, ":") == NULL) { // just "l2cap"
352 peer->port = DEFAULT_L2CAP_PORT;
353 } else {
354 peer->port = atoi(strPort);
355 }
356 DEBUG2("[DS]: Peer %d: L2CAP Server mode, port %d", peer->id, peer->port);
357
358 #endif
359
360 } else if ((strPort = strstr(portIn, UNIX_SOCKET)) != NULL) {
361
362 strPort += strlen(UNIX_SOCKET);
363
364 peer->mode = CLIENT_NOAT;
365 peer->portStr = stringNew(strPort);
366
367 DEBUG2("[DS]: Peer %d: Serial Client mode (no AT). Use device %s", peer->id, peer->portStr->str);
368
369 } else if ((strPort = strstr(portIn, STDIN_STREAM)) != NULL) {
370
371 peer->mode = SERVER_STDIN;
372 DEBUG2("[DS]: Peer %d: stdin", peer->id);
373
374 } else if ((strPort = strstr(portIn, RFCOMM_DEVICE)) != NULL) {
375
376 if (!(strlen(portIn) == strlen(RFCOMM_DEVICE) + BT_ADDR_LEN + 3 || // 00:12:EF:32:21:1A:p
377 strlen(portIn) == strlen(RFCOMM_DEVICE) + BT_ADDR_LEN + 4) || // 00:12:EF:32:21:1A:pp
378 portIn[strlen(RFCOMM_DEVICE)] != ':' ||
379 portIn[strlen(RFCOMM_DEVICE) + BT_ADDR_LEN + 1] != ':') {
380 printf("ERROR: Improper connect string !\n");
381 free(peer);
382 return EXIT_ABORT;
383 }
384
385 char sBtAddr[18];
386 strncpy(sBtAddr,portIn + strlen(RFCOMM_DEVICE) + 1,17);
387 sBtAddr[17] = '\0';
388
389 peer->mode = CLIENT_RFCOMM;
390 peer->port = atoi(portIn + strlen(RFCOMM_DEVICE) + BT_ADDR_LEN + 2);
391 peer->portStr = stringNew(sBtAddr);
392
393 DEBUG2("[DS]: Peer %d: Serial Client mode, device %s : %d", peer->id, peer->portStr->str, peer->port);
394
395 } else if ((strPort = strstr(portIn, WEB_SOCKET)) != NULL) {
396
397 strPort += strlen(WEB_SOCKET);
398
399 // check is it port
400 char * ch = strPort;
401 int isPort = 1;
402 while (*ch != '\0') {
403 if (isdigit(*ch)) {
404 ch++;
405 } else {
406 isPort = 0;
407 break;
408 }
409 }
410
411 if (isPort) {
412
413 peer->mode = SERVER_WEB;
414 peer->port = atoi(strPort);
415 if (peer->port <= 0) {
416 printf("ERROR: Improper port to use !\n");
417 ERROR2("[DS]: Improper port %d to use", peer->port);
418 free(peer);
419 return EXIT_ABORT;
420 }
421
422 DEBUG2("[DS]: Peer %d: Web Server mode. Use port %d", peer->id, peer->port);
423
424 } else {
425 logger(L_ERR,"[DS]: can not determine web server port");
426 free(peer);
427 return EXIT_ABORT;
428 }
429
430 } else if ((strPort = strstr(portIn, CMXML_SOCKET)) != NULL) {
431
432 strPort += strlen(CMXML_SOCKET);
433
434 // check is it port
435 char * ch = strPort;
436 int isPort = 1;
437 while (*ch != '\0') {
438 if (isdigit(*ch)) {
439 ch++;
440 } else {
441 isPort = 0;
442 break;
443 }
444 }
445
446 if (isPort) {
447
448 peer->mode = SERVER_CMXML;
449 peer->port = atoi(strPort);
450
451 DEBUG2("[DS]: Peer %d: XML Server mode. Use port %d", peer->id, peer->port);
452
453 } else {
454 logger(L_ERR,"[DS]: can not determine XML server port");
455 free(peer);
456 return EXIT_ABORT;
457 }
458
459 } else if ((strPort = strstr(portIn, AT_DEVICE)) != NULL) {
460
461 strPort += strlen(AT_DEVICE);
462
463 peer->mode = CLIENT_AT;
464 peer->portStr = stringNew(strPort);
465 DEBUG2("[DS]: Peer %d: Serial Client mode. Use device %s", peer->id, peer->portStr->str);
466
467 } else if (strstr(portIn, AVAHI_USE)) {
468
469 // do nothing
470 logger(L_DBG, "[DS]: Avahi flag is ON");
471 freePeer(peer);
472 return EXIT_OK;
473
474 } else {
475
476 peer->mode = CLIENT_AT;
477 peer->portStr = stringNew(portIn);
478 DEBUG2("[DS]: Peer %d: Default: use serial Client mode. Use device %s", peer->id, peer->portStr->str);
479 }
480
481 _connections = listSingleAppend(_connections, peer);
482
483 return EXIT_OK;
484 }
485
writeToFrontEnd(const char * buf)486 void writeToFrontEnd(const char *buf)
487 {
488 SingleList* list = _connections;
489 while (list) {
490 ConnectInfo* peer = (ConnectInfo*) list->data;
491 if (peer->mode == FRONT_END) {
492 feWrite(peer,buf);
493 }
494 list = listSingleNext(list);
495 }
496 }
497
connectNotify(int peer)498 void connectNotify(int peer)
499 {
500 DEBUG2("[DS]: connectNotify");
501 writeToFrontEnd("Connected");
502 sendEventToExecutor(peer, ID_EVT_CONNECT);
503 }
504
needStoreState()505 static boolean_t needStoreState()
506 {
507 int connCnt = 0;
508
509 SingleList* list = _connections;
510 while (list) {
511 ConnectInfo* peer = (ConnectInfo*) list->data;
512
513 if (peer->mode == SERVER_WEB ||
514 peer->mode == SERVER_CMXML) {
515 connCnt += 2; // need to store state in any case if WEB/CMXML is used
516 } else if (peer->mode == SERVER_TCP ||
517 peer->mode == SERVER_BT ||
518 peer->mode == CLIENT_NOAT||
519 peer->mode == SERVER_UX
520 #ifdef USE_L2CAP
521 || peer->mode == SERVER_L2CAP
522 #endif
523 ) {
524 connCnt += 1;
525 }
526 if (connCnt > 1) {
527 break;
528 }
529 list = listSingleNext(list);
530 }
531 DEBUG2("[DS]: needStoreState() %s", (connCnt > 1 ? "Y" : "N"));
532 return (connCnt > 1 ? BOOL_YES : BOOL_NO);
533 }
534
haveConnectionless()535 boolean_t haveConnectionless()
536 {
537 SingleList* list = _connections;
538 while (list) {
539 ConnectInfo* peer = (ConnectInfo*) list->data;
540 if (peer->mode == SERVER_WEB || peer->mode == SERVER_CMXML) {
541 return 1;
542 }
543 list = listSingleNext(list);
544 }
545 return 0;
546 }
547
definePeers()548 int definePeers()
549 {
550 DEBUG2("[DS]: definePeers");
551 char* peers = getDevice();
552
553 // split peers by ','
554 char *sep;
555 char* peer = peers;
556 int ret = EXIT_ABORT;
557
558 while ((sep = index(peer,','))) {
559
560 *sep = '\0';
561
562 INFO2("[DS]: definePeers() peer %s", peer);
563 int ret1 = addPeer(peer);
564 if (ret1 != EXIT_ABORT) {
565 ret = EXIT_OK;
566 }
567
568 peer = sep+1;
569
570 }
571
572 int ret1 = addPeer(peer);
573 if (ret1 != EXIT_ABORT) {
574 ret = EXIT_OK;
575 }
576
577 free(peers);
578
579 int fePort = getFrontEnd();
580 if (fePort > 0) {
581 ConnectInfo* peer = allocPeer(BOOL_NO);
582 peer->mode = FRONT_END;
583 peer->port = fePort;
584 DEBUG2("[DS]: Add FE peer id=%d on port %d", peer->id, peer->port);
585
586 _connections = listSingleAppend(_connections, peer);
587 }
588
589 if (needStoreState()) {
590 DEBUG2("[DS]: definePeers() init state");
591 initState();
592 }
593 if (haveConnectionless()) {
594 DEBUG2("[DS]: definePeers() connectionless connectNotify");
595 connectNotify(0);
596 }
597
598 DEBUG2("[DS]: definePeers done %d (peers #%d)", ret, listSingleLength(_connections));
599 return ret;
600 }
601
openPeers()602 int openPeers()
603 {
604 DEBUG2("[DS]: openPeers %d", listSingleLength(_connections));
605
606 int ret = EXIT_OK;
607 SingleList* list = _connections;
608 while (list) {
609 ConnectInfo* peer = (ConnectInfo*) list->data;
610
611 if (peer->state == PEER_DISCONNECTED) {
612 INFO2("[DS]: Open peer with mode %d", peer->mode);
613
614 int ret1 = _peerHandlers[peer->mode].openConnection(peer);
615
616 DEBUG2("[DS]: openPeers peer %d ret code %d", peer->id, ret1);
617
618 if (peer->state != PEER_DISCONNECTED) { // for TCP (etc.) connection still can be in DISCONNECT
619 INFO2("[DS]: Open peer %d connect fdescriptor %d", peer->id, _peerHandlers[peer->mode].descriptor(peer));
620 }
621
622 if (ret1 != EXIT_NOK) {
623 ret = ret1;
624 }
625 } else {
626 DEBUG2("[DS]: openPeers peer %d have state %s", peer->id,
627 (peer->state == PEER_DISCONNECTED ? "DISCONNECTED" :
628 (peer->state == PEER_WAIT_LISTEN ? "WAIT_LISTEN" :
629 (peer->state == PEER_WAIT_ACCEPT ? "PEER_WAIT_ACCEPT" :
630 (peer->state == PEER_CONNECTED ? "CONNECTED" : "UNKNOWN")
631 )
632 )
633 )
634 );
635 }
636 list = listSingleNext(list);
637 }
638 return ret;
639 }
640
closePeers(int final)641 void closePeers(int final)
642 {
643 DEBUG2("[DS]: closePeers %d", final);
644 SingleList* list = _connections;
645 while (list) {
646 ConnectInfo* peer = (ConnectInfo*) list->data;
647
648 _peerHandlers[peer->mode].closeConnection(peer, final);
649
650 list = listSingleNext(list);
651 }
652 }
653
disconnectPeersInternal(ConnectInfo * peer)654 int disconnectPeersInternal(ConnectInfo* peer)
655 {
656 int canForceExit = 0;
657
658 dMessage* dm = allocDMessage();
659 dm->type = DM_SET;
660 dm->subtype = ID_SET_DISCONN;
661 dm->size = 16;
662 dm->value = strdup(CMD_STR_DISCONNECT);
663
664 if (peer->mode == SERVER_BT) {
665
666 if (getIViewer() || getBemused()) {
667 canForceExit = 1;
668 } else {
669 logger(L_INF, "[DS]: Got exit event: send disconnect message");
670 if (btsppWrite(peer, dm) != EXIT_OK) {
671 canForceExit = 1;
672 }
673 }
674
675 } else if (peer->mode == SERVER_TCP) {
676
677 if (getIViewer() || getBemused()) {
678 canForceExit = 1;
679 } else {
680 logger(L_INF, "[DS]: Got exit event: send disconnect message");
681 if (socketWrite(peer, dm) != EXIT_OK) {
682 canForceExit = 1;
683 }
684 }
685
686 } else if (peer->mode == SERVER_UX) {
687
688 logger(L_INF, "[DS]: Got exit event: send disconnect message");
689 if (socketWrite(peer, dm) != EXIT_OK) {
690 canForceExit = 1;
691 }
692
693 } else if (peer->mode == CLIENT_RFCOMM ||
694 peer->mode == CLIENT_AT) {
695
696 int fd = _peerHandlers[peer->mode].descriptor(peer);
697 if (fd >= 0) {
698 sendCMER(fd, CMER_OFF);
699 }
700 canForceExit = 1;
701
702 #ifdef USE_L2CAP
703 } else if (peer->mode == SERVER_L2CAP) {
704
705 if (l2capWrite(peer, dm) != EXIT_OK) {
706 canForceExit = 1;
707 }
708
709 #endif
710 } else if (peer->mode == SERVER_WEB ||
711 peer->mode == SERVER_CMXML) {
712 canForceExit = 1;
713 } else if (peer->mode == FRONT_END) {
714 canForceExit = 1;
715 }
716
717 free(dm->value);
718 free(dm);
719
720 DEBUG2("[DS]: disconnectPeersInternal %d mode=%d can force exit=%d", peer->id, peer->mode, canForceExit);
721 return canForceExit;
722 }
723
724 // retuns 1/-1
725 // return code is used in case of exit only
disconnectPeers(void)726 int disconnectPeers(void)
727 {
728 DEBUG2("[DS]: disconnectPeers");
729 int ret = 1;
730 SingleList* list = _connections;
731 while (list) {
732
733 ConnectInfo* peer = (ConnectInfo*) list->data;
734
735 int ret1 = disconnectPeersInternal(peer);
736 if (ret1 != 1) {
737 ret = ret1;
738 }
739 list = listSingleNext(list);
740 }
741 DEBUG2("[DS]: disconnectPeers can force exit=%d", ret);
742 return ret;
743 }
744
745 // Do some tuning of opened connection
746 // (used in client mode)
setupPeersPre(void)747 int setupPeersPre(void)
748 {
749 DEBUG2("[DS]: setupPeersPre");
750 int ret = -1;
751 SingleList* list = _connections;
752 while (list) {
753
754 ConnectInfo* peer = (ConnectInfo*) list->data;
755
756 int retS = _peerHandlers[peer->mode].setupPre(peer);
757
758 if (retS != -1) {
759 ret = retS;
760 }
761 list = listSingleNext(list);
762 }
763 return ret;
764 }
765
isDataCacheable(int what)766 static boolean_t isDataCacheable(int what)
767 {
768 if (what == ID_SET_BG ||
769 what == ID_SET_CAPTION ||
770 what == ID_SET_FG ||
771 what == ID_SET_FONT ||
772 what == ID_SET_ICONS ||
773 what == ID_SET_HINTS ||
774 what == ID_SET_LAYOUT ||
775 what == ID_SET_STATUS ||
776 what == ID_SET_TITLE ||
777 what == ID_SET_VOLUME ||
778 what == ID_SET_COVER) {
779 return BOOL_YES;
780 } else {
781 return BOOL_NO;
782 }
783 }
784
785 // 0/1
isDataOld(ConnectInfo * peer,int subtype,const char * data,int size)786 int isDataOld(ConnectInfo* peer, int subtype, const char* data, int size)
787 {
788 if (!isDataCacheable(subtype)) {
789 return 0; // consider as new value
790 }
791 if (!peer->cache) {
792 return 0; // consider as new value
793 }
794 if (subtype >= ID_SET_MAX) {
795 return 0; // consider as new value
796 }
797
798 //DEBUG2("isDataOld(): %d -> %s", subtype, (data?data:"NULL"));
799
800 DCache* cache = peer->cache;
801
802 int isOld = 1;
803 if (cache->lastValues[subtype] == NULL) {
804 isOld = 0; // consider as new value
805 } else if (cache->lastValues[subtype] != NULL &&
806 (cache->lastValuesSize[subtype] != size ||
807 memcmp(cache->lastValues[subtype], data, cache->lastValuesSize[subtype]) != 0)) {
808
809 free(cache->lastValues[subtype]);
810 cache->lastValues[subtype] = NULL;
811 cache->lastValuesSize[subtype] = -1;
812
813 isOld = 0; // consider as new value
814 }
815
816 if (isOld == 0) {
817 cache->lastValues[subtype] = (char*) calloc(size + 1, 1);
818 memcpy(cache->lastValues[subtype], data, size);
819 cache->lastValuesSize[subtype] = size;
820 }
821 return isOld;
822 }
823
824 //
825 // Default peer writer
826 //
writePeer(int fd,const char * buffer,int n)827 static int writePeer(int fd, const char* buffer, int n)
828 {
829 int nbytes = write(fd,buffer,n);
830 if (nbytes < 0) {
831 ERROR2("[DS]: writePeer() error %d",errno);
832 errnoDebug("[DS]: writePeer() write ",errno); // testing debug
833 }
834 return nbytes;
835 }
836
peerWrite(ConnectInfo * peer,const dMessage * msg)837 static int peerWrite(ConnectInfo* peer, const dMessage* msg)
838 {
839 const char* command = msg->value;
840 int count = msg->size;
841
842 if (!command || count <= 0) {
843 return EXIT_OK;
844 }
845
846 if (strcmp("End();",command) == 0) { // used only for WEB/CMXML
847 return EXIT_OK;
848 }
849
850 if (msg->type == DM_SET) {
851 if (isDataOld(peer, msg->subtype, command, count)) {
852 INFO2("[DS]: Skip to send the same data to peer %d", peer->id);
853 return EXIT_OK;
854 }
855 }
856
857 int fd = _peerHandlers[peer->mode].descriptor(peer);
858 if (fd < 0) {
859 return EXIT_NOK;
860 }
861
862 return (writePeer(fd, command, count) > 0 ? EXIT_OK : EXIT_NOK);
863
864 }
865
866 //
867 // Sync peer after connect
868 //
syncPeer(ConnectInfo * peer)869 static void syncPeer(ConnectInfo* peer)
870 {
871 if (peer->mode == SERVER_TCP ||
872 peer->mode == SERVER_BT ||
873 peer->mode == SERVER_UX ||
874 peer->mode == CLIENT_NOAT
875 #ifdef USE_L2CAP
876 || peer->mode == SERVER_L2CAP
877 #endif
878 ) {
879
880 ERROR2("[DS]: syncPeer %d", peer->id);
881
882 static struct {
883 string_t* (*hooks[6]) (int) ; // CF,TX,LI,FM,WM,EF
884 } _renderHooks[] = {
885 // CF TX LI FM WM EF
886 /* SERVER_TCP+ */{{renderCtrlForm, renderTextForm, renderListForm, NULL, renderWmanForm, renderEditForm}}
887 };
888
889
890 int f = curForm() - 1;
891 INFO2("[DS]: syncPeer form %d", f);
892
893 if (_renderHooks[0].hooks[f]) {
894 string_t* content = _renderHooks[0].hooks[f](peer->port);
895 if (content) {
896
897 //char buf[256];
898 //strncpy(buf,content->str,255);
899 //buf[255] = '\0';
900 //INFO2("[DS]: syncPeer sync content %s", buf);
901
902 int fd = _peerHandlers[peer->mode].descriptor(peer);
903 if (fd >= 0) {
904 INFO2("[DS]: syncPeer write to peer %d %d", f, fd);
905 writePeer(fd, content->str, content->len);
906 }
907 stringFree(content, BOOL_YES);
908 }
909 }
910
911 if (curForm() == CF) { // take care about cover
912
913 int fd = _peerHandlers[peer->mode].descriptor(peer);
914 if (fd >= 0) {
915
916 string_t* page = renderCtrlFormCover();
917 writePeer(fd, page->str, page->len);
918 stringFree(page, BOOL_YES);
919
920 const char* nc = cfNamedCover();
921 const char* cv = cfCover();
922
923 if (!nc && cv) {
924
925 string_t* page = stringNew("Set(cover,noname,");
926 stringAppend(page, cv);
927 stringAppend(page, ");");
928
929 eMessage* em = (eMessage*) malloc(sizeof(eMessage));
930 em->peer = peer->id;
931 em->type = EM_STRING;
932 em->value = strdup(page->str);
933
934 stringFree(page, BOOL_YES);
935
936 sendToExecutor(em);
937 }
938 }
939 }
940 }
941 }
942
943 //
944 // Default peer reader
945 //
readPeer(int fd,char * buffer,int max)946 int readPeer(int fd, char* buffer, int max)
947 {
948 int nbytes = read(fd, buffer, max);
949 if (nbytes < 0) { // Read error
950 //ERROR2("[DS]: readPeer() error %d",errno);
951 errnoDebug("[DS]: readPeer() read ",errno); // testing debug
952 } else if (nbytes == 0) {
953 DEBUG2("[DS]: readPeer() EOF");
954 }
955
956 //DEBUG2("[DS]: readPeer() got >%s< %d", buffer, nbytes);
957 return nbytes;
958 }
959
960 //
961 // TCP peer reader with quirk for iViewer
962 //
readIVPeer(int fd,char * buffer,int max)963 static int readIVPeer(int fd, char* buffer, int max)
964 {
965 //DEBUG2("[DS]: readIVPeer()");
966 int nbytes = read(fd, buffer, max);
967
968 if (nbytes < 0) { // Read error
969 ERROR2("[DS]: readIVPeer() error %d",errno);
970 errnoDebug("[DS]: readIVPeer() read ",errno); // testing debug
971 } else if (nbytes == 0) {
972 DEBUG2("[DS]: readIVPeer() EOF");
973 } else {
974 boolean_t heartbeat = BOOL_NO;
975 char *hptr = buffer;
976 //DEBUG2("[DS]: readIVPeer() got %s", buffer);
977
978 //while ((hptr = strstr(hptr, "h=0"))) {
979 if (strstr(hptr, "h=0")) {
980 // do not erase it from read data, because it used as disconnect timer in cfg.files
981 /*
982 *hptr = '\r';
983 hptr++;
984 *hptr = '\r';
985 hptr++;
986 *hptr = '\r';
987 */
988
989 heartbeat = BOOL_YES;
990 }
991
992 hptr = buffer;
993 while ((hptr = strchr(hptr, '\3'))) { // end-of-text marker in CommandFusion
994 // replace \3 separator to \r
995 *hptr = '\r';
996 }
997
998 if (heartbeat) {
999 DEBUG2("[DS]: readIVPeer() send iViever heartbeat");
1000 writeIViewerHeartbeat(fd);
1001 }
1002 }
1003
1004 //DEBUG2("[DS]: readIVPeer() got >%s< %d", buffer, nbytes);
1005 return nbytes;
1006 }
1007
1008 //
1009 // CLIENT_NOAT peer reader
1010 // in IR communication a lot of 'empty' chars (= -1) could be added
1011 //
readIRPeer(int fd,char * buffer,int max)1012 static int readIRPeer(int fd, char* buffer, int max)
1013 {
1014 int nbytes = read(fd, buffer, max);
1015 if (nbytes < 0) { // Read error
1016 ERROR2("[DS]: readIRPeer() error %d",errno);
1017 errnoDebug("[DS]: readIRPeer() read ",errno); // testing debug
1018 } else if (nbytes == 0) {
1019 DEBUG2("[DS]: readIRPeer() EOF");
1020 } else {
1021 buffer[nbytes] = '\0';
1022 char * k2 = buffer;
1023 while (*k2 != '\0') {
1024 if (*k2 == -1) {
1025 *k2 = '\r';
1026 }
1027 k2++;
1028 }
1029 }
1030
1031 //DEBUG2("[DS]: readIRPeer() got >%s< %d", buffer, nbytes);
1032 return nbytes;
1033 }
1034
1035 //
1036 // BT peer reader with quirk for Bemused
1037 // must read VOLM command with an additional value byte
1038 // SHFL/REPT _can_ follow with an additional byte - so don not bother about them
1039 //
readBmPeer(int fd,char * buffer,int max)1040 static int readBmPeer(int fd, char* buffer, int max)
1041 {
1042 int nbytes = read(fd, buffer, max);
1043 if (nbytes < 0) { // Read error
1044 ERROR2("[DS]: readBmPeer() error %d",errno);
1045 errnoDebug("[DS]: readBmPeer() read ",errno); // testing debug
1046 } else if (nbytes == 0) {
1047 DEBUG2("[DS]: readBmPeer() EOF");
1048 } else {
1049 boolean_t heartbeat = BOOL_NO;
1050 char *hptr = NULL;
1051 while ((hptr = strstr(buffer, "CHCK"))) {
1052 // erase it from read data
1053 *hptr = '\r';
1054 hptr++;
1055 *hptr = '\r';
1056 hptr++;
1057 *hptr = '\r';
1058 hptr++;
1059 *hptr = '\r';
1060
1061 heartbeat = BOOL_YES;
1062 }
1063
1064 if (heartbeat) {
1065 DEBUG2("[DS]: readBmPeer() send Bemused heartbeat");
1066 writeBemusedHeartbeat(fd);
1067 }
1068
1069 // hack to make it work correctly with Bemused clients
1070 char c = '\r';
1071 if (nbytes >=4 &&
1072 (strncmp((buffer+nbytes-4), "VOLM", 4) == 0 //|| // read only VOLM without value to set
1073 /*strncmp((buffer+nbytes-4), "SHFL", 4) == 0 ||
1074 strncmp((buffer+nbytes-4), "REPT", 4) == 0*/)) {
1075
1076 int ret;
1077 if ((ret = bt_readchar(fd,&c,500000)) < 0) {
1078 DEBUG2("[DS]: readBmPeer: Bemused hack: read < 0");
1079 } else {
1080 sprintf(tmp, "[DS]: readBmPeer: Bemused hack: read >%c<", c);
1081 logger(L_DBG,tmp);
1082 buffer[nbytes] = c;
1083 nbytes++;
1084 }
1085 }
1086
1087 }
1088
1089 //DEBUG2("[DS]: readBmPeer() got >%s< %d", buffer, nbytes);
1090 return nbytes;
1091 }
1092
readPeersInternal(ConnectInfo * peer)1093 static int readPeersInternal(ConnectInfo* peer)
1094 {
1095 //INFO2("[DS]: readPeersInternal peer %d", peer->id);
1096 char buf[MAXCMDLEN];
1097 memset(buf, 0, MAXCMDLEN);
1098
1099 int len = 0;
1100 //printf("read_command\n");
1101
1102 if (peer->mode == SERVER_STDIN) {
1103
1104 len = stdinRead(buf,MAXCMDLEN); // returns EOF in case of error and EOF
1105 if (len > 0 && len != EOF) {
1106 DEBUG2("[DS]: read_command SERVER_STDIN %d %s\n", len, buf);
1107 parseCommand(peer->id, buf);
1108 }
1109 } else if (peer->mode == SERVER_WEB || peer->mode == SERVER_CMXML) {
1110
1111 len = checkWebPort(buf, MAXCMDLEN); // returns EOF in case of error and EOF
1112 if (len > 0 && len != EOF) {
1113 DEBUG2("[DS]: read_command WEB/CMXML %d %s\n", len, buf);
1114 parseCommand(peer->id, buf);
1115 }
1116
1117 } else {
1118
1119 /* use select() for others
1120 int fd = _peerHandlers[peer->mode].descriptor(peer);
1121 if (peer->state == PEER_CONNECTED && fd >= 0) {
1122
1123 char* p = buf;
1124
1125 while (len < MAXCMDLEN) {
1126 char c;
1127 int ch = bt_readchar(fd,&c,100);
1128
1129 INFO2("[DS]: readPeersInternal read from peer with mode %d got %d", peer->mode, ch);
1130
1131 if (ch == EOF) {
1132 INFO2("[DS]: readPeersInternal EOF peer with mode %d", peer->mode);
1133 buf[0] = 0;
1134 peer->state = PEER_DISCONNECTED;
1135 break;
1136 } else if (ch == EOF-1) {
1137 break;
1138 } else if (ch >= 0 && (c == '\r' || c == ';')) {
1139 break;
1140 } else if (ch >= 0 && c != '\r' && c != ';') {
1141 *p++ = c;
1142 len++;
1143 }
1144 }
1145
1146 buf[len] = '\0';
1147 stringAppend(buffer,"\r"); // separator
1148 stringAppend(buffer,buf);
1149 }
1150 */
1151
1152 }
1153 return len;
1154 }
1155
doReadPeer(ConnectInfo * peer,int fd)1156 static int doReadPeer(ConnectInfo* peer, int fd)
1157 {
1158 char buf[MAXCMDLEN];
1159 memset(buf, 0, MAXCMDLEN);
1160
1161 //DEBUG2("[DS]: doReadPeer() ready to read from fd %d (peer %d)", fd, peer->id);
1162
1163 int rc = 0;
1164
1165 if (peer->mode == SERVER_TCP && getIViewer()) {
1166 rc = readIVPeer(fd, buf, MAXCMDLEN);
1167 } else if (peer->mode == SERVER_BT && getBemused()) {
1168 rc = readBmPeer(fd, buf, MAXCMDLEN);
1169 } else if (peer->mode == CLIENT_NOAT) {
1170 rc = readIRPeer(fd, buf, MAXCMDLEN);
1171 } else if (peer->mode == CLIENT_RFCOMM || peer->mode == CLIENT_AT) {
1172 rc = atRead(peer, buf, MAXCMDLEN);
1173 } else if (peer->mode == FRONT_END) {
1174 return feRead(fd);
1175 } else {
1176 rc = readPeer(fd, buf, MAXCMDLEN);
1177 }
1178
1179 if (rc <= 0) { // EOF or error
1180 DEBUG2("[DS]: doReadPeer() EOF or error fd %d (peer %d), reset connection", fd, peer->id);
1181 _peerHandlers[peer->mode].resetConnection(peer);
1182 return EOF;
1183 }
1184
1185 parseCommand(peer->id, buf);
1186 return 1;
1187 }
1188
processPeers()1189 int processPeers()
1190 {
1191 //DEBUG2("[DS]: processPeers()");
1192
1193 fd_set read_fds;
1194 FD_ZERO(&read_fds);
1195
1196 struct timeval tv;
1197 tv.tv_sec = 0;
1198 tv.tv_usec = 100;
1199
1200 int max_fd = -1;
1201 int readCnt = 0;
1202
1203 SingleList* list = _connections;
1204 while (list) {
1205 ConnectInfo* peer = (ConnectInfo*) list->data;
1206
1207 //DEBUG2("[DS]: processPeers() peer %d state %s", peer->mode,
1208 // (peer->state == PEER_CONNECTED ? "CONNECTED" :
1209 // (peer->state == PEER_WAIT_LISTEN ? "WAIT_LISTEN" : "WAIT_ACCEPT")));
1210
1211 if ((peer->state == PEER_CONNECTED &&
1212 !(peer->mode == SERVER_STDIN || peer->mode == SERVER_WEB || peer->mode == SERVER_CMXML)) ||
1213 peer->state == PEER_WAIT_LISTEN ||
1214 peer->state == PEER_WAIT_ACCEPT) {
1215
1216 int fd = _peerHandlers[peer->mode].descriptor(peer);
1217 //DEBUG2("[DS]: processPeers() peer %d connected %s state (fd=%d)", peer->id,
1218 // (peer->state == PEER_CONNECTED ? "CONNECTED" :
1219 // (peer->state == PEER_WAIT_LISTEN ? "WAIT_LISTEN" : "WAIT_ACCEPT")), fd);
1220
1221 if (fd >= 0) {
1222 FD_SET(fd, &read_fds);
1223 //} else { web, xml can have that
1224 // DEBUG2("[DS]: processPeers() peer with mode %d improper descriptor", peer->mode);
1225 }
1226 if (max_fd < fd) {
1227 max_fd = fd;
1228 }
1229 }
1230 list = listSingleNext(list);
1231 }
1232
1233 if (max_fd >= 0) { // have some peers
1234
1235 int rc = select(max_fd + 1, &read_fds, NULL, NULL, &tv);
1236
1237 //if (rc != 0) {
1238 // DEBUG2("[DS]: processPeers() select()=%d, maxfd=%d",rc,max_fd);
1239 //}
1240
1241 if (rc == 0) { // timeout
1242 //DEBUG2("[DS]: processPeers() no data from select()");
1243 } else if (rc < 0) { // some error
1244 //DEBUG2("[DS]: processPeers() error %d", errno);
1245 errnoDebug("[DS]: processPeers() select ",errno); // testing debug
1246 } else {
1247 //DEBUG2("[DS]: --------------------------------------------");
1248 //DEBUG2("[DS]: processPeers() got data from select()");
1249
1250 list = _connections;
1251 while (list) {
1252
1253 ConnectInfo* peer = (ConnectInfo*) list->data;
1254
1255 int fd = _peerHandlers[peer->mode].descriptor(peer);
1256
1257 if (fd >= 0) {
1258
1259 //DEBUG2("[DS]: processPeers() %d descriptor on peer %d", fd, peer->id);
1260
1261 if (FD_ISSET(fd, &read_fds)) {
1262
1263 //DEBUG2("[DS]: processPeers() FD_ISSET %d descriptor", fd);
1264
1265 if (peer->state == PEER_CONNECTED) {
1266
1267 //DEBUG2("[DS]: processPeers() peer %d readable", peer->id);
1268 int rr = doReadPeer(peer, fd);
1269 if (rr == EOF) {
1270
1271 freeCachedData(peer);
1272
1273 int cnum = countConnections();
1274 DEBUG2("[DS]: processPeers() countConnections %d", cnum);
1275
1276 // no more connections
1277 if (cnum == 0) {
1278 DEBUG2("[DS]: processPeers() disconnect notify");
1279 return EOF;
1280 }
1281 } else if (rr > 0) {
1282 readCnt++;
1283 }
1284
1285 } else if (peer->state == PEER_WAIT_LISTEN) {
1286
1287 DEBUG2("[DS]: processPeers() peer %d listenable", peer->id);
1288 if (_peerHandlers[peer->mode].listenConnection(peer) < 0) {
1289 DEBUG2("[DS]: readPeers() fails to listen from peer %d (fd=%d)", peer->id, fd);
1290 }
1291
1292 } else if (peer->state == PEER_WAIT_ACCEPT) {
1293
1294 //logger(L_DBG,"[DS]: ************ new connection **********");
1295 DEBUG2("[DS]: processPeers() accept connection from peer %d (fd=%d)", peer->id, fd);
1296 if (_peerHandlers[peer->mode].acceptConnection(peer) == EXIT_OK) {
1297
1298 int cnum = countOtherConnections(peer);
1299 DEBUG2("[DS]: processPeers() countOtherConnections %d", cnum);
1300
1301 // do this only on first connect
1302 if (cnum == 0) {
1303 DEBUG2("[DS]: processPeers() connectNotify");
1304 connectNotify(peer->id);
1305 } else {
1306 freeCachedData(peer);
1307 if (needStoreState()) {
1308 syncPeer(peer);
1309 }
1310 }
1311
1312 // too late, because syncPeer() was already done
1313 //if (peer->state == PEER_CONNECTED) {
1314 // _peerHandlers[peer->mode].setupPost(peer);
1315 //}
1316 }
1317 }
1318 //} else {
1319 // DEBUG2("[DS]: processPeers() no FD_ISSET on peer %d", peer->id);
1320 }
1321 //} else {
1322 // DEBUG2("[DS]: processPeers() no descriptor on peer %d", peer->id);
1323 }
1324 list = listSingleNext(list);
1325 }
1326 }
1327 //} else {
1328 // DEBUG2("[DS]: processPeers() no peers to read");
1329 }
1330
1331 //DEBUG2("[DS]: processPeers() special cases");
1332 // special cases
1333 list = _connections;
1334 while (list) {
1335 ConnectInfo* peer = (ConnectInfo*) list->data;
1336 if (peer->state == PEER_CONNECTED || peer->mode == SERVER_WEB || peer->mode == SERVER_CMXML) {
1337 int rc = readPeersInternal(peer);
1338 if (rc < 0 || rc == EOF) { // EOF or error
1339 DEBUG2("[DS]: processPeers() EOF or error special case (peer %d), close connection", peer->id);
1340 _peerHandlers[peer->mode].closeConnection(peer, 0);
1341 return EOF;
1342 } else if (rc > 0){
1343 readCnt++;
1344 }
1345 // Only stdin, web and cmxml goes here. None of them can have state PEER_WAIT_ACCEPT
1346 //} else if (peer->state == PEER_WAIT_ACCEPT) {
1347 // //DEBUG2("[DS]: processPeers() TODO aa1");
1348 }
1349 list = listSingleNext(list);
1350 }
1351
1352 //DEBUG2("[DS]: processPeers() return %d", readCnt);
1353 return readCnt;
1354 }
1355
writePeers(dMessage * dm)1356 int writePeers(dMessage* dm)
1357 {
1358 INFO2("[DS]: writePeers");
1359 int ret = EXIT_NOK;
1360
1361 if (needStoreState()) {
1362 updateState(dm);
1363 }
1364
1365 SingleList* list = _connections;
1366 while (list) {
1367 ConnectInfo* peer = (ConnectInfo*) list->data;
1368
1369 if (dm->peer == PEER_ANY || peer->id == dm->peer) {
1370 if (peer->state == PEER_CONNECTED ||
1371 peer->mode == SERVER_WEB ||
1372 peer->mode == SERVER_CMXML) {
1373
1374 INFO2("[DS]: write to peer %d (%d)", peer->id, dm->peer);
1375
1376 int ret1 = (_peerHandlers[peer->mode].writeConnection == NULL ?
1377 EXIT_NOK : _peerHandlers[peer->mode].writeConnection(peer, dm));
1378
1379 if (ret1 != EXIT_NOK) {
1380 ret = ret1;
1381 }
1382 }
1383 }
1384 list = listSingleNext(list);
1385 }
1386
1387 //INFO2("[DS]: write result %s", (ret == EXIT_NOK? "NOK": "OK"));
1388 return ret;
1389 }
1390
writeByteInternal(int fd,int byte)1391 static int writeByteInternal(int fd, int byte)
1392 {
1393 unsigned char byte2write[2];
1394 byte2write[0] = (unsigned char) byte;
1395 byte2write[1] = '\0';
1396
1397 if (write(fd, byte2write, 1) < 0) {
1398 logger(L_ERR, "error writing bytes");
1399 return EXIT_NOK;
1400 }
1401 return EXIT_OK;
1402 }
1403
peerWriteBytes(ConnectInfo * peer,const char * command)1404 static int peerWriteBytes(ConnectInfo* peer, const char* command)
1405 {
1406 int fd = _peerHandlers[peer->mode].descriptor(peer);
1407 if (fd < 0) {
1408 logger(L_DBG,"[DS]: peerWriteBytes() no connection data");
1409 return EXIT_NOK;
1410 }
1411
1412 // send command
1413 if (fd >= 0 && command && command[0]) {
1414
1415 char byteStr[MAXCKPDLEN];
1416 memset(byteStr,0,MAXCKPDLEN);
1417
1418 strncpy(byteStr,command,MAXCKPDLEN-1);
1419
1420 DEBUG2("[DS]: peerWriteBytes >%s<", byteStr);
1421
1422 char* bStr = strtok(byteStr,",");
1423 while (bStr != NULL) {
1424
1425 //DEBUG2("[DS]: Next byte is >%s<", bStr);
1426
1427 char bStripped[4];
1428
1429 while (*bStr == ' ') {
1430 bStr++;
1431 }
1432 int i = 0;
1433 while (*bStr != ' ' && i < 3) { // 0 < ... < 256
1434 bStripped[i] = *bStr;
1435 bStr++;
1436 i++;
1437 }
1438 bStripped[i] = '\0';
1439
1440 //DEBUG2("[DS]: Next byte is >%s<", bStripped);
1441
1442 if (writeByteInternal(fd, atoi(bStripped)) != EXIT_OK) {
1443 logger(L_DBG,"[DS]: Fails in peerWriteBytes()");
1444 return EXIT_NOK;
1445 }
1446
1447 bStr = strtok(NULL,",");
1448 }
1449 }
1450 //logger(L_DBG, "peerWriteBytes EXIT");
1451 return EXIT_OK;
1452 }
1453
writeBytesPeers(char * command)1454 int writeBytesPeers(char* command)
1455 {
1456 int ret = EXIT_NOK;
1457 SingleList* list = _connections;
1458 while (list) {
1459 ConnectInfo* peer = (ConnectInfo*) list->data;
1460 if (peer &&
1461 peer->state == PEER_CONNECTED &&
1462 _peerHandlers[peer->mode].writeBytesConnection != NULL) {
1463
1464 INFO2("[DS]: write bytes to peer %d", peer->mode);
1465 int ret1 = _peerHandlers[peer->mode].writeBytesConnection(peer, command);
1466
1467 if (ret1 != EXIT_NOK) {
1468 ret = ret1;
1469 }
1470 }
1471 list = listSingleNext(list);
1472 }
1473 return ret;
1474 }
1475
1476 //
1477 // In case of WEB/CMXML it is enougn to send name of file, not full content
1478 //
writeFilePeers(dMessage * dm)1479 int writeFilePeers(dMessage* dm)
1480 {
1481 INFO2("[DS]: DM_SETFILE %d %s %s %s", dm->peer, (char*) dm->value, dm->file, dm->scaled);
1482
1483 if (needStoreState()) {
1484 updateState(dm);
1485 }
1486
1487 int size = 0;
1488 char* buf = NULL;
1489 dMessage* dm2 = NULL;
1490 boolean_t evaluated = BOOL_NO;
1491
1492 SingleList* list = _connections;
1493 while (list) {
1494
1495 ConnectInfo* peer = (ConnectInfo*) list->data;
1496
1497 if (dm->peer == PEER_ANY || dm->peer == peer->id) {
1498 if (peer->state == PEER_CONNECTED || peer->mode == SERVER_WEB || peer->mode == SERVER_CMXML) {
1499 INFO2("[DS]: write file to peer %d", peer->id);
1500
1501 if (peer->mode == SERVER_WEB || peer->mode == SERVER_CMXML) {
1502
1503 // nothing, state stored by updateState(...) above
1504
1505 } else {
1506
1507 if (evaluated == BOOL_NO) {
1508
1509 evaluated = BOOL_YES;
1510
1511 // read data from file
1512 buf = readFromFile(dm->value, dm->scaled, &size);
1513
1514 INFO2("[DS]: writeFilePeers got from file %s %d bytes", dm->scaled, size);
1515
1516 if (buf && size > 0) {
1517
1518 dm2 = allocDMessage();
1519 dm2->type = DM_SET;
1520 dm2->subtype = dm->subtype;
1521 dm2->value = buf;
1522 dm2->size = size;
1523 }
1524 }
1525
1526 if (dm2) {
1527 if (_peerHandlers[peer->mode].writeConnection != NULL) {
1528 _peerHandlers[peer->mode].writeConnection(peer, dm2);
1529 }
1530 }
1531 }
1532 }
1533 }
1534 list = listSingleNext(list);
1535 }
1536 freeDMessage(dm2);
1537 return EXIT_OK;
1538 }
1539
writeCKPD(dMessage * dm)1540 int writeCKPD(dMessage* dm)
1541 {
1542 //logger(L_DBG, "[DS]: Send CKPD");
1543 SingleList* list = _connections;
1544 while (list) {
1545
1546 ConnectInfo* peer = (ConnectInfo*) list->data;
1547
1548 if (dm->peer == PEER_ANY || dm->peer == peer->id) {
1549 if (peer->state == PEER_CONNECTED &&
1550 (peer->mode == CLIENT_RFCOMM || peer->mode == CLIENT_AT)) {
1551
1552 int fd = _peerHandlers[peer->mode].descriptor(peer);
1553 if (fd >= 0) {
1554 logger(L_DBG, "[DS]: Send CKPD");
1555 sendSeq(fd, (char*) dm->value);
1556 }
1557 }
1558 }
1559 list = listSingleNext(list);
1560 }
1561 return EXIT_OK;
1562 }
1563
1564 /*int writeCMER(dMessage* dm)
1565 {
1566 logger(L_DBG, "[DS]: Send CMER");
1567
1568 SingleList* list = _connections;
1569 while (list) {
1570
1571 ConnectInfo* peer = (ConnectInfo*) list->data;
1572
1573 if (peer->state == PEER_CONNECTED &&
1574 (peer->mode == CLIENT_RFCOMM || peer->mode == CLIENT_AT)) {
1575
1576 int fd = _peerHandlers[peer->mode].descriptor(peer);
1577 if (fd >= 0) {
1578 sendCMER(fd, dm->size);
1579 }
1580 }
1581 list = listSingleNext(list);
1582 }
1583 return EXIT_OK;
1584 }*/
1585
1586 //
1587 // returns EXIT_OK if at least one connection exists
1588 //
connected()1589 int connected()
1590 {
1591 SingleList* list = _connections;
1592 while (list) {
1593
1594 ConnectInfo* peer = (ConnectInfo*) list->data;
1595 if (peer->state == PEER_CONNECTED && peer->mode != FRONT_END) {
1596 return EXIT_OK;
1597 /*} else if (peer->mode == SERVER_WEB || peer->mode == SERVER_CMXML) { // connection-less, check clients num
1598 _WebConnection* cn = (_WebConnection*) peer->connectionData;
1599 if (cn) {
1600 if (haveClients(cn)) {
1601 return EXIT_OK;
1602 }
1603 }*/
1604 }
1605
1606 list = listSingleNext(list);
1607 }
1608 return EXIT_NOK;
1609 }
1610
1611 //
1612 // Send heartbeat message to all TCP connection.
1613 // Suppose we have only one connection to iViewer
1614 //
socketWriteByte(int fd,int byte)1615 static int socketWriteByte(int fd, int byte)
1616 {
1617 unsigned char byte2write[2];
1618 byte2write[0] = (unsigned char) byte;
1619 byte2write[1] = '\0';
1620
1621 if (write(fd, byte2write, 1) < 0) {
1622 logger(L_ERR, "error writing byte to socket");
1623 return EXIT_NOK;
1624 }
1625 return EXIT_OK;
1626 }
1627
writeIViewerHeartbeat(int fd)1628 static void writeIViewerHeartbeat(int fd)
1629 {
1630 // reply message is h=1\03
1631 socketWriteByte(fd, 104); // h
1632 socketWriteByte(fd, 61); // =
1633 socketWriteByte(fd, 49); // 1
1634 socketWriteByte(fd, 3); // \03
1635 }
1636
writeBemusedHeartbeat(int fd)1637 static void writeBemusedHeartbeat(int fd)
1638 {
1639 // reply message to "CHCK" is "Y"
1640 writePeer(fd, "Y", 1);
1641 }
1642
writeHeartbeat(ConnectInfo * peer)1643 void writeHeartbeat(ConnectInfo* peer)
1644 {
1645 int fd = _peerHandlers[peer->mode].descriptor(peer);
1646 if (fd >= 0) {
1647 writeIViewerHeartbeat(fd);
1648 }
1649 }
1650
sendIViewerHeartbeat(void)1651 void sendIViewerHeartbeat(void)
1652 {
1653 SingleList* list = _connections;
1654 while (list) {
1655
1656 ConnectInfo* peer = (ConnectInfo*) list->data;
1657 if (peer->state == PEER_CONNECTED &&
1658 peer->mode == SERVER_TCP) { // iViewer connection can be TCP only
1659
1660 writeHeartbeat(peer);
1661 }
1662 list = listSingleNext(list);
1663 }
1664 }
1665
1666 //
1667 // returns EXIT_OK if there are only client peers and all peers unconnected
1668 //
needExit()1669 int needExit()
1670 {
1671 SingleList* list = _connections;
1672 while (list) {
1673 ConnectInfo* cn = (ConnectInfo*) list->data;
1674
1675 if (cn->state == PEER_CONNECTED) {
1676 return EXIT_NOK;
1677 }
1678
1679 if (!(cn->mode == CLIENT_RFCOMM ||
1680 cn->mode == CLIENT_AT ||
1681 cn->mode == CLIENT_ILIRC)) {
1682 return EXIT_NOK;
1683 }
1684 list = listSingleNext(list);
1685 }
1686 return EXIT_OK;
1687 }
1688
1689 //
1690 // returns EXIT_OK if there are web/cmxml peer exists
1691 //
needFinalizer()1692 int needFinalizer()
1693 {
1694 SingleList* list = _connections;
1695 while (list) {
1696 ConnectInfo* cn = (ConnectInfo*) list->data;
1697
1698 if (cn->mode == SERVER_WEB || cn->mode == SERVER_CMXML) {
1699 return EXIT_OK;
1700 }
1701 list = listSingleNext(list);
1702 }
1703 return EXIT_NOK;
1704 }
1705
1706 //
1707 // returns EXIT_OK if there are AT peer exists
1708 //
1709 // TODO: mutex ?
needAtMainMenuReturn(int peerid)1710 int needAtMainMenuReturn(int peerid)
1711 {
1712 SingleList* list = _connections;
1713 while (list) {
1714 ConnectInfo* cn = (ConnectInfo*) list->data;
1715 if (cn->id == peerid && (cn->mode == CLIENT_RFCOMM || cn->mode == CLIENT_AT)) {
1716 return EXIT_OK;
1717 }
1718 list = listSingleNext(list);
1719 }
1720 return EXIT_NOK;
1721 }
1722
1723 //
1724 // returns EXIT_OK if there are server-mode peer exists
1725 //
isServerMode()1726 int isServerMode()
1727 {
1728 SingleList* list = _connections;
1729 while (list) {
1730 ConnectInfo* cn = (ConnectInfo*) list->data;
1731
1732 if (cn->mode == SERVER_BT ||
1733 cn->mode == SERVER_TCP ||
1734 cn->mode == SERVER_WEB ||
1735 cn->mode == SERVER_CMXML ||
1736 cn->mode == SERVER_UX ||
1737 cn->mode == CLIENT_NOAT
1738 #ifdef USE_L2CAP
1739 || cn->mode == SERVER_L2CAP
1740 #endif
1741 ) {
1742 return EXIT_OK;
1743 }
1744 list = listSingleNext(list);
1745 }
1746 return EXIT_NOK;
1747 }
1748
1749 //
1750 // returns EXIT_OK if there are server-mode (no WEB/CMXML) peer exists
1751 //
1752 /*int isServerModeNoWeb()
1753 {
1754 SingleList* list = _connections;
1755 while (list) {
1756 ConnectInfo* cn = (ConnectInfo*) list->data;
1757
1758 if (cn->mode == SERVER_BT ||
1759 cn->mode == SERVER_TCP ||
1760 cn->mode == SERVER_UX ||
1761 cn->mode == CLIENT_NOAT
1762 #ifdef USE_L2CAP
1763 || cn->mode == SERVER_L2CAP
1764 #endif
1765 ) {
1766 return EXIT_OK;
1767 }
1768 list = listSingleNext(list);
1769 }
1770 return EXIT_NOK;
1771 }
1772
1773 int isWebServer()
1774 {
1775 return needFinalizer();
1776 }
1777
1778 //
1779 // returns EXIT_OK if there are at-mode peer exists
1780 //
1781 int isAtMode()
1782 {
1783 SingleList* list = _connections;
1784 while (list) {
1785 ConnectInfo* cn = (ConnectInfo*) list->data;
1786
1787 if (cn->mode == CLIENT_RFCOMM ||
1788 cn->mode == CLIENT_AT ||
1789 cn->mode == CLIENT_ILIRC) {
1790 return EXIT_OK;
1791 }
1792 list = listSingleNext(list);
1793 }
1794 return EXIT_NOK;
1795 }*/
1796
1797 //
1798 // returns EXIT_OK if there are CLIENT_RFCOMM/CLIENT_AT peer exists
1799 //
isAtModeDuplex()1800 int isAtModeDuplex()
1801 {
1802 SingleList* list = _connections;
1803 while (list) {
1804 ConnectInfo* cn = (ConnectInfo*) list->data;
1805
1806 if (cn->mode == CLIENT_RFCOMM ||
1807 cn->mode == CLIENT_AT) {
1808 return EXIT_OK;
1809 }
1810 list = listSingleNext(list);
1811 }
1812 return EXIT_NOK;
1813 }
1814
1815 //
1816 // In iViewer mode returns TCP port (search for the first TCP connection)
1817 //
getIViewerTcpPort(void)1818 int getIViewerTcpPort(void)
1819 {
1820 int port = -1;
1821
1822 SingleList* list = _connections;
1823 while (list) {
1824 ConnectInfo* cn = (ConnectInfo*) list->data;
1825
1826 if (cn->mode == SERVER_TCP && cn->port >= 0) { // SERVER_TCP handle also Unix (file) sockets
1827 return cn->port;
1828 }
1829 list = listSingleNext(list);
1830 }
1831
1832 return port;
1833 }
1834
checkActiveCall()1835 boolean_t checkActiveCall()
1836 {
1837 SingleList* list = _connections;
1838 while (list) {
1839 ConnectInfo* cn = (ConnectInfo*) list->data;
1840
1841 if (cn->mode == CLIENT_RFCOMM) {
1842 if (rfcommCheckActiveCall(cn)) {
1843 return BOOL_YES;
1844 }
1845 } else if (cn->mode == CLIENT_AT) {
1846 if (serialCheckActiveCall(cn)) {
1847 return BOOL_YES;
1848 }
1849 }
1850 list = listSingleNext(list);
1851 }
1852 return BOOL_NO;
1853 }
1854
hasActiveCall()1855 boolean_t hasActiveCall()
1856 {
1857 SingleList* list = _connections;
1858 while (list) {
1859 ConnectInfo* cn = (ConnectInfo*) list->data;
1860
1861 if (cn->mode == CLIENT_RFCOMM) {
1862 if (rfcommHasActiveCall(cn)) {
1863 return BOOL_YES;
1864 }
1865 } else if (cn->mode == CLIENT_AT) {
1866 if (serialHasActiveCall(cn)) {
1867 return BOOL_YES;
1868 }
1869 }
1870 list = listSingleNext(list);
1871 }
1872 return BOOL_NO;
1873 }
1874
getClientSize(int peer,int fd)1875 void getClientSize(int peer, int fd)
1876 {
1877 DEBUG2("[DS]: Detect cover size for peer %d", peer);
1878
1879 int n = write(fd,CMD_STR_GETCOVERSZ,16);
1880 if (n < 0) {
1881 logger(L_ERR, "[DS]: Error on detect cover size (w)");
1882 return;
1883 }
1884
1885 char buf[MAXCMDLEN];
1886 memset(buf, 0, MAXCMDLEN);
1887
1888 n = readPeer(fd, buf, MAXCMDLEN);
1889 if (n <= 0) { // EOF or error
1890 logger(L_ERR, "[DS]: Error on detect cover size (r)");
1891 return;
1892 }
1893 buf[n] = '\0';
1894
1895 // Msg:CoverSize(xxx,);
1896 DEBUG2("[DS]: Cover size reply for peer %d is %s", peer, buf);
1897 char* pos = strstr(buf,"CoverSize(");
1898 if (!pos) {
1899 logger(L_ERR, "[DS]: Error on detect cover size (p)");
1900 return;
1901 }
1902 pos += 10; // "CoverSize("
1903 char *p2 = pos;
1904 while (isdigit(*p2)) {
1905 p2++;
1906 }
1907 *p2 = '\0';
1908
1909 int sz = atoi(pos);
1910 DEBUG2("[DS]: Cover size for peer %d is %d", peer, sz);
1911
1912 DEBUG2("[DS]: Detect screen size for peer %d", peer);
1913
1914 n = write(fd,CMD_STR_GETSCREENSZ,17);
1915 if (n < 0) {
1916 logger(L_ERR, "[DS]: Error on detect screen size (w)");
1917 return;
1918 }
1919
1920 n = readPeer(fd, buf, MAXCMDLEN);
1921 if (n <= 0) { // EOF or error
1922 logger(L_ERR, "[DS]: Error on detect screen size (r)");
1923 return;
1924 }
1925 buf[n] = '\0';
1926
1927 // Msg:SizeX(xxx,);SizeY(xxx);
1928 DEBUG2("[DS]: Cover size reply for peer %d is %s", peer, buf);
1929 pos = strstr(buf,"SizeX(");
1930 if (!pos) {
1931 logger(L_ERR, "[DS]: Error on detect screen X size");
1932 return;
1933 }
1934 pos += 6; // "SizeX("
1935 p2 = pos;
1936 while (isdigit(*p2)) {
1937 p2++;
1938 }
1939 *p2 = '\0';
1940
1941 int xsz = atoi(pos);
1942 DEBUG2("[DS]: X screen size for peer %d is %d", peer, xsz);
1943
1944
1945 pos = strstr(buf,"SizeY(");
1946 if (!pos) {
1947 logger(L_ERR, "[DS]: Error on detect screen Y size (attempt 1)");
1948 // try again
1949 n = readPeer(fd, buf, MAXCMDLEN);
1950 if (n <= 0) { // EOF or error
1951 logger(L_ERR, "[DS]: Error on detect screen size (r)");
1952 return;
1953 }
1954 buf[n] = '\0';
1955
1956 pos = strstr(buf,"SizeY(");
1957 if (!pos) {
1958 logger(L_ERR, "[DS]: Error on detect screen Y size");
1959 return;
1960 }
1961 }
1962 pos += 6; // "SizeY("
1963 p2 = pos;
1964 while (isdigit(*p2)) {
1965 p2++;
1966 }
1967 *p2 = '\0';
1968
1969 int ysz = atoi(pos);
1970 DEBUG2("[DS]: Y screen size for peer %d is %d", peer, ysz);
1971
1972 customizePeer(peer, xsz, ysz, sz);
1973 }
1974