mirror of
https://github.com/eddyem/BTA_utils.git
synced 2026-08-13 19:49:24 +03:00
212 lines
5.6 KiB
C
212 lines
5.6 KiB
C
/*
|
|
* bta_json.c - create socket and reply bta data
|
|
*
|
|
* Copyright 2013 Edward V. Emelianoff <eddy@sao.ru>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <strings.h>
|
|
#include "bta_json.h"
|
|
|
|
// wait for child to avoid zombies
|
|
static void wait_for_child(int sig){
|
|
pid_t child;
|
|
while((child = waitpid(-1, NULL, WNOHANG)) > 0);
|
|
}
|
|
|
|
// search a first word after needle without spaces
|
|
char* stringscan(char *str, char *needle){
|
|
char *a, *e;
|
|
char *end = str + strlen(str);
|
|
a = strstr(str, needle);
|
|
if(!a) return NULL;
|
|
a += strlen(needle);
|
|
while (a < end && (*a == ' ' || *a == '\r' || *a == '\t' || *a == '\r')) a++;
|
|
if(a >= end) return NULL;
|
|
e = strchr(a, ' ');
|
|
if(e) *e = 0;
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Parce data received from client
|
|
* In case of http request we send all avaiable data
|
|
* In case of request from client socket, parce it
|
|
* Socket's request have structure like "par1<del>par2<del>..."
|
|
* where "pars" are names of bta_pars fields
|
|
* <del> is delimeter: one of symbols " &\t\n"
|
|
* @param buf - incoming data
|
|
* @param L - length of buf
|
|
* @param par - returned parameters structure
|
|
*/
|
|
void parce_incoming_buf(char *buf, size_t L, bta_pars *par){
|
|
char *tok, *got;
|
|
memset(par, 0, sizeof(bta_pars));
|
|
DBG("got data: %s", buf);
|
|
// http request - send all if get == "bta_par"
|
|
// if get == "bta_par?a&b&c...", change buf to pars
|
|
if((got = stringscan(buf, "GET"))){
|
|
size_t LR = strlen(RESOURCE);
|
|
if(strcmp(got, RESOURCE) == 0){
|
|
par->ALL = true;
|
|
return;
|
|
}else if(strncmp(got, RESOURCE, LR) == 0) buf = &got[LR+1];
|
|
else exit(-1); // wrong request
|
|
}
|
|
// request from socket -> check all parameters
|
|
tok = strtok(buf, " &\t\n");
|
|
if(!tok) return;
|
|
do{
|
|
#define checkpar(val) if(strcasecmp(tok, val) == 0){par->val = true; continue;}
|
|
checkpar(vel);
|
|
checkpar(diff);
|
|
checkpar(corr);
|
|
checkpar(mtime);
|
|
checkpar(meteo);
|
|
checkpar(target);
|
|
checkpar(p2mode);
|
|
checkpar(eqcoor);
|
|
checkpar(telmode);
|
|
checkpar(sidtime);
|
|
checkpar(horcoor);
|
|
checkpar(valsens);
|
|
checkpar(telfocus);
|
|
#undef checkpar
|
|
}while((tok = strtok(NULL, " &\t\n")));
|
|
}
|
|
|
|
void handle(int newsock){
|
|
size_t buflen = 4095;
|
|
char buffer[buflen + 1];
|
|
bta_pars par;
|
|
do{
|
|
ssize_t readed = recv(newsock, buffer, buflen, 0);
|
|
if(readed < 1) break; // client closed or error
|
|
parce_incoming_buf(buffer, readed, &par);
|
|
#ifdef EBUG
|
|
#define checkpar(val) if(par.val){ fprintf(stderr, "par: %s\n", val); }
|
|
if(par.ALL){ fprintf(stderr, "par: ALL\n"); }
|
|
checkpar(vel);
|
|
checkpar(diff);
|
|
checkpar(corr);
|
|
checkpar(mtime);
|
|
checkpar(sidtime);
|
|
checkpar(meteo);
|
|
checkpar(target);
|
|
checkpar(p2mode);
|
|
checkpar(eqcoor);
|
|
checkpar(telmode);
|
|
checkpar(horcoor);
|
|
checkpar(valsens);
|
|
checkpar(telfocus);
|
|
#undef checkpar
|
|
#endif // EBUG
|
|
make_JSON(newsock, &par);
|
|
}while(!par.ALL);
|
|
close(newsock);
|
|
}
|
|
|
|
int main(int argc, char **argv){
|
|
int sock;
|
|
struct sigaction sa;
|
|
struct addrinfo hints, *res, *p;
|
|
int reuseaddr = 1;
|
|
check4running(argv, PIDFILE, NULL);
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = AF_INET;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_flags = AI_PASSIVE;
|
|
if(getaddrinfo(NULL, PORT, &hints, &res) != 0){
|
|
perror("getaddrinfo");
|
|
return 1;
|
|
}
|
|
struct sockaddr_in *ia = (struct sockaddr_in*)res->ai_addr;
|
|
char str[INET_ADDRSTRLEN];
|
|
inet_ntop(AF_INET, &(ia->sin_addr), str, INET_ADDRSTRLEN);
|
|
printf("port: %u, addr: %s\n", ntohs(ia->sin_port), str);
|
|
// loop through all the results and bind to the first we can
|
|
for(p = res; p != NULL; p = p->ai_next){
|
|
if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
|
|
perror("socket");
|
|
continue;
|
|
}
|
|
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){
|
|
perror("setsockopt");
|
|
return -1;
|
|
}
|
|
if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){
|
|
close(sock);
|
|
perror("bind");
|
|
continue;
|
|
}
|
|
break; // if we get here, we must have connected successfully
|
|
}
|
|
if(p == NULL){
|
|
// looped off the end of the list with no successful bind
|
|
fprintf(stderr, "failed to bind socket\n");
|
|
exit(2);
|
|
}
|
|
// Listen
|
|
if(listen(sock, BACKLOG) == -1) {
|
|
perror("listen");
|
|
return 1;
|
|
}
|
|
freeaddrinfo(res);
|
|
// Set up the signal handler
|
|
sa.sa_handler = wait_for_child;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_RESTART;
|
|
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
|
|
perror("sigaction");
|
|
return 1;
|
|
}
|
|
// OK, all done, now we can daemonize
|
|
#ifndef EBUG // daemonize only in release mode
|
|
if(daemon(1, 0)){
|
|
perror("daemon()");
|
|
exit(1);
|
|
}
|
|
#endif // EBUG
|
|
// Main loop
|
|
while(1){
|
|
struct sockaddr_in their_addr;
|
|
socklen_t size = sizeof(struct sockaddr_in);
|
|
int newsock = accept(sock, (struct sockaddr*)&their_addr, &size);
|
|
int pid;
|
|
if(newsock == -1) return 0;
|
|
pid = fork();
|
|
if(pid == 0){
|
|
// Child process
|
|
close(sock);
|
|
handle(newsock);
|
|
return 0;
|
|
}else{
|
|
// Parent process
|
|
if(pid == -1) return 1;
|
|
else{
|
|
close(newsock);
|
|
DBG("Create child: %d", pid);
|
|
}
|
|
}
|
|
}
|
|
close(sock);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ËÏÎÅÃ ÆÁÊÌÁ
|