apps/sctl/sctl.cgi.cpp

Go to the documentation of this file.
00001 #include <iostream>
00002 #include <string>
00003 #include <map>
00004 #include <list>
00005 #include <fstream>
00006 
00007 #include <stdlib.h>
00008 #include <sys/types.h>
00009 #include <sys/stat.h>
00010 #include <fcntl.h>
00011 #include <unistd.h>
00012 #include <syslog.h>
00013 
00014 #include <sys/socket.h>
00015 #include <sys/param.h>
00016 #include <unistd.h>
00017 #include <sys/ioctl.h>
00018 #include <netinet/in.h>
00019 #include <net/if.h>
00020 #include <netdb.h>
00021 #include <arpa/inet.h>
00022 #include <linux/if_ether.h>
00023 #include <sched.h>
00024 
00025 using namespace std;
00026 
00027 #define _KILLALL "/usr/bin/killall"
00028 #define _FPCF "/usr/local/bin/fpcf"
00029 #define _STR    "/usr/local/bin/str"
00030 #define _CONF_RUN       "/var/state/streamer.conf"
00031 #define _CONF   "/etc/streamer.conf"
00032 #define _STATUS_XML     "/var/state/streamer.xml"
00033 
00034 #define HEADER_TEXT     0x00
00035 #define HEADER_XML      0x01
00036 
00037 #define STREAMER_ELF    "str"
00038 #define STREAMER_LOCK   "/dev/stream"
00039 
00040 #define DEFAULT_PORT    "20000"
00041 #define DEFAULT_ADDR    "232.0.0.1"
00042 
00043 void header(int type) {
00044         cout << "HTTP/1.0 200 OK" << endl;
00045         cout << "Pragma: no-cache" << endl;
00046         if(type == HEADER_TEXT)
00047                 cout << "Content-Type: text/plain" << endl;
00048         if(type == HEADER_XML)
00049                 cout << "Content-Type: text/xml" << endl;
00050         cout << endl;
00051 }
00052 
00053 bool parse_string(const string &str, char delimiter, string &left, string &right) {
00054     left = "";
00055     right = "";
00056     int i = str.find(delimiter);
00057     if(i > 0 && i < (int)str.length()) {
00058         const char *c = str.c_str();
00059         left.insert(0, c, i);
00060         right.insert(0, &c[i + 1], str.length() - i - 1);
00061     } else
00062         left = str;
00063         if(left == "")
00064                 return false;
00065         else
00066                 return true;
00067 }
00068 
00069 bool streamer_start(map<string, string>);
00070 bool streamer_stop(void);
00071 void stream_status(void);
00072 bool conf_save(map<string, string>);
00073 void conf_load(ostream &stream);
00074 string get_self_ip(string);
00075 void stream_status_to_file(map<string, string> opts);
00076 
00077 int main(int argc, char *argv[]) {
00078 //      const char *b;
00079         string cmd;
00080         map<string, string> opts;
00081 
00082         string method = getenv("REQUEST_METHOD");
00083         string query = getenv("QUERY_STRING");
00084         string uri = getenv("REQUEST_URI");
00085 
00086         string left, right;
00087         while(parse_string(query, '&', left, right)) {
00088                 string n, v;
00089                 parse_string(left, '=', n, v);
00090                 opts.insert(pair<string, string>(n, v));
00091                 query = right;
00092         }
00093 
00094         bool res = false;
00095         if(opts["cmd"] == "start") {
00096                 header(HEADER_TEXT);
00097                 res = streamer_start(opts);
00098                 stream_status_to_file(opts);
00099         }
00100         if(opts["cmd"] == "stop") {
00101                 header(HEADER_TEXT);
00102                 res = streamer_stop();
00103         }
00104         if(opts["cmd"] == "status") {
00105                 header(HEADER_XML);
00106                 stream_status();
00107         }
00108 /*
00109         if(opts["cmd"] == "save") {
00110                 header(HEADER_TEXT);
00111                 res = conf_save(opts);
00112         }
00113         if(opts["cmd"] == "load") {
00114                 header(HEADER_XML);
00115                 conf_load(cout);
00116         }
00117 */
00118 //      cout << "result: " << res << endl;
00119 /*
00120         if(opts["cmd"] == "status") {
00121                 cout << "cmd == status" << endl;
00122         }
00123 */
00124         return 0;
00125 }
00126 
00127 /************************************************
00128  *
00129  * start/stop streamer
00130  *
00131  * run specified program with arguments as daemon
00132  */
00133 bool streamer_is_run(void) {
00134         int fd = open(STREAMER_LOCK, O_RDONLY);
00135         if(fd < 0)
00136                 return true;
00137         close(fd);
00138         return false;
00139 }
00140 
00141 bool run_daemon(string prog, list<string> args) {
00142         int null_fd;
00143         int pid;
00144         if((pid = fork()) < 0) {
00145 //              cout << "fork() fail!" << endl;
00146                 return false;
00147         } else
00148                 if(pid != 0) {
00149                         // wait 2 sec here while a streamer is not run
00150                         int c = 0;
00151                         while(!streamer_is_run() && c < 20) {
00152                                 usleep(100000);
00153                                 c++;
00154                         }
00155 //                      cout << "fork() ok!" << endl;
00156                         return true;
00157                 }
00158         // prepare to daemon
00159         setsid();
00160         chdir("/");
00161         umask(0);
00165         fflush(stdout);
00166         fflush(stderr);
00167         null_fd=open("/dev/null",O_RDWR);
00168         dup2(null_fd, 0);
00169         dup2(null_fd, 1);
00170         close(null_fd);
00171 //      fprintf (stdout, "\ntest output to stdout\n");
00172 //      fprintf (stderr, "\ntest output to stderr (after test output to stdout)\n");
00173 //      close(0);
00174 //      close(1);
00175 //      close(2);
00176         int l = args.size() + 1;
00177         char **a = (char **)malloc(sizeof(char *) * l);
00178         int i = 0;
00179         for(list<string>::iterator it = args.begin(); it != args.end(); it++, i++)
00180                 a[i] = const_cast<char *>((*it).c_str());
00181         a[i] = NULL;
00182         execvp(prog.c_str(), a);
00183         return false;
00184 }
00185 
00186 bool streamer_start(map<string, string> opts) {
00187         if(streamer_is_run()) {
00188 //              cout << "streamer is already running" << endl;
00189                 return true;
00190         }
00191         // prepare arguments
00192         string t;
00193         list<string> args;
00194         args.push_back("str");
00195         string mcast_transport;
00196         if(opts["addr"] != "")
00197                 mcast_transport = opts["addr"];
00198         if(opts["port"] != "") {
00199                 mcast_transport += ":";
00200                 mcast_transport += opts["port"];
00201         }
00202 /*
00203         if(opts["addr"] != "") {
00204                 args.push_back("-a");
00205                 args.push_back(opts["addr"]);
00206         }
00207         if(opts["port"] != "") {
00208                 args.push_back("-p");
00209                 args.push_back(opts["port"]);
00210         }
00211 */
00212         if(opts["fps"] != "") {
00213                 args.push_back("-f");
00214                 args.push_back(opts["fps"]);
00215         }
00216         t = opts["transport"];
00217         if(t != "") {
00218                 if(t == "mcast") {
00219                         args.push_back("-m");
00220                         if(mcast_transport != "")
00221                                 args.push_back(mcast_transport);
00222                 }
00223                 if(t == "ucast")
00224                         args.push_back("-u");
00225         }
00226         if(opts["ttl"] != "") {
00227                 args.push_back("-t");
00228                 args.push_back(opts["ttl"]);
00229         }
00230         // and run
00231         conf_save(opts);
00232         return run_daemon(_STR, args);
00233 }
00234 // Temporary fix - calling "fpcf -jpeg d" as a daemon resulted in errno 9 (EBADF)
00235 // (directly calling that or from php script was OK)
00236 // so I just copied portion of fpcf here
00237 // #include <asm/elphel/c313a.h> - needed to be actually included, not these two lines below
00238 // AF
00239 #define CMOSCAM_IOCTYPE 124
00240 #define IO_CCAM_JPEG    0x08 // JPEG-compressor related commands
00241 void stop_compressor(void) {
00242  int devfd = open("/dev/sensorpars", O_RDONLY);
00243  ioctl(devfd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG ), 13);
00244  close (devfd);
00245 }
00246 
00247 bool streamer_stop(void) {
00248         if(streamer_is_run() == false)
00249                 return true;
00250         list<string> args_kill;
00251         args_kill.push_back("killall");
00252         args_kill.push_back("-9");
00253         args_kill.push_back("str");
00254         bool res = run_daemon(_KILLALL, args_kill);
00255         /* wait, when streamer stopped */
00256         if(res) {
00257                 while(streamer_is_run())
00258                         sched_yield();
00259         } else
00260                 return false;
00261         /* reset horrible drivers */
00262 // thank you. AF
00263    stop_compressor();
00264    return true;
00265 /*
00266         list<string> args_fpcf;
00267         args_fpcf.push_back("fpcf");
00268         args_fpcf.push_back("-jpeg");
00269         args_fpcf.push_back("d");
00270         return run_daemon(_FPCF, args_fpcf);
00271 */
00272 }
00273 
00274 /************************************************
00275  *
00276  * load/save config
00277  *
00278  */
00279 
00280 bool conf_save(map<string, string> opts) {
00281         ofstream ofile;
00282         ofile.open(_CONF_RUN);
00283         string t;
00284         t = opts["transport"];
00285         if(t == "mcast") {
00286                 ofile << "name=multicast" << endl;
00287                 ofile << "n=1" << endl;
00288         } else {
00289                 ofile << "name=unicast" << endl;
00290                 ofile << "n=2" << endl;
00291         }
00292         ofile << "dest_port=";
00293         if(opts["port"] != "")
00294                 ofile << opts["port"] << endl;
00295         else
00296                 ofile << DEFAULT_PORT << endl;
00297         ofile << "dest_ip=";
00298         if(opts["addr"] != "")
00299                 ofile << opts["addr"] << endl;
00300         else
00301                 ofile << DEFAULT_ADDR << endl;
00302         ofile << "autostart=";
00303         if(opts["autostart"] == "true" || opts["autostart"] == "1")
00304                 ofile << "true" << endl;
00305         else
00306                 ofile << "false" << endl;
00307         ofile << "fps=";
00308         if(opts["fps"] != "") {
00309                 ofile << opts["fps"] << endl;
00310                 ofile << "maxfps=1" << endl;
00311         } else {
00312                 ofile << "0" << endl;
00313                 ofile << "maxfps=0" << endl;
00314         }
00315         ofile.close();
00316         return true;
00317 }
00318 
00319 void conf_load(ostream &out) {
00320         out << "<streamer>" << endl;
00321         map<string, string> conf;
00322         ifstream ifile(_CONF);
00323         string part;
00324         while(!ifile.eof()) {
00325                 char in = ifile.get();
00326                 if(in == '\r' || in == '\n') {
00327                         if(part == "")
00328                                 continue;
00329                         string n, v;
00330                         parse_string(part, '=', n, v);
00331                         out << "<" << n << ">";
00332                         out << v;
00333                         out << "</" << n << ">" << endl;
00334                         part = "";
00335                         continue;
00336                 }
00337                 part += in;
00338         }
00339         ifile.close();
00340         out << "</streamer>" << endl;
00341 }
00342 
00343 void stream_status_to_file(map<string, string> opts) {
00344         ofstream ofile(_STATUS_XML);
00345         string t;
00346         t = opts["transport"];
00347         string _n = "1";
00348         string _name = "multicast";
00349         string _m = "1";
00350         if(t != "mcast") {
00351                 _n = "2";
00352                 _name = "unicast";
00353                 _m = "0";
00354         }
00355         ofile << "<streamer>" << endl;
00356         ofile << "<n>" << _n << "</n>" << endl;
00357         ofile << "<name>" << _name << "</name>" << endl;
00358         ofile << "<rtsp>";
00359         ofile << "<ip>"  << get_self_ip("eth0") << "</ip>";
00360         ofile << "<port>554</port>";
00361         ofile << "</rtsp>" << endl;
00362         ofile << "<rtp>";
00363         ofile << "<ip>" << opts["addr"] << "</ip>";
00364         ofile << "<port>" << opts["port"] << "</port>";
00365         ofile << "<multicast>" << _m << "</multicast>";
00366         ofile << "</rtp>" << endl;
00367         ofile << "</streamer>" << endl;
00368 }
00369 
00370 void stream_status(void) {
00371         bool is_run = streamer_is_run();
00372         if(is_run) {
00373                 ifstream ifile(_STATUS_XML);
00374 //              char buf[256];
00375                 while(!ifile.eof()) {
00376                         string z;
00377                         ifile >> z;
00378                         cout << z;
00379 //                      int l = ifile.read(buf, 255);
00380 //                      cout.write(buf, l);
00381                 }
00382                 return;
00383         }
00384         cout << "<streamer>" << endl;
00385         cout << "<n>0</n>" << endl;
00386         cout << "<name>multicast</name>" << endl;
00387         cout << "<rtsp>";
00388         cout << "<ip>"  << get_self_ip("eth0") << "</ip>";
00389         cout << "<port>554</port>";
00390         cout << "</rtsp>" << endl;
00391         cout << "<rtp>";
00392         cout << "<ip>232.0.0.1</ip>";
00393         cout << "<port>20000</port>";
00394         cout << "<multicast>1</multicast>";
00395         cout << "</rtp>" << endl;
00396         cout << "</streamer>" << endl;
00397 }
00398 
00399 string get_self_ip(string iface) {
00400         struct ifreq ifr;
00401         struct sockaddr_in *sin;
00402         int fd;
00403 
00404         fd = socket(AF_INET, SOCK_DGRAM, 0);
00405         if(fd < 0)
00406                 return "0.0.0.0";
00407 
00408         memset(&ifr, 0, sizeof(ifr));
00409         strcpy(ifr.ifr_name, "eth0");
00410 
00411         if(ioctl(fd, SIOCGIFADDR, &ifr) != 0)
00412                 return "0.0.0.0";
00413 
00414         sin = (struct sockaddr_in*)(ifr.ifr_addr.sa_data + 2);
00415         struct in_addr src_addr4 = *(struct in_addr*)sin;
00416         close(fd);
00417         return inet_ntoa(src_addr4);
00418 }

Generated on Fri Nov 28 00:06:22 2008 for elphel by  doxygen 1.5.1