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