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
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
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 return 0;
00125 }
00126
00127
00128
00129
00130
00131
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
00146 return false;
00147 } else
00148 if(pid != 0) {
00149
00150 int c = 0;
00151 while(!streamer_is_run() && c < 20) {
00152 usleep(100000);
00153 c++;
00154 }
00155
00156 return true;
00157 }
00158
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
00172
00173
00174
00175
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
00189 return true;
00190 }
00191
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
00204
00205
00206
00207
00208
00209
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
00231 conf_save(opts);
00232 return run_daemon(_STR, args);
00233 }
00234
00235
00236
00237
00238
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
00256 if(res) {
00257 while(streamer_is_run())
00258 sched_yield();
00259 } else
00260 return false;
00261
00262
00263 stop_compressor();
00264 return true;
00265
00266
00267
00268
00269
00270
00271
00272 }
00273
00274
00275
00276
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
00375 while(!ifile.eof()) {
00376 string z;
00377 ifile >> z;
00378 cout << z;
00379
00380
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 }