Main Page | Namespace List | Class Hierarchy | Data Structures | File List | Data Fields | Globals | Related Pages

acq2xx_server.cpp

Go to the documentation of this file.
00001 /* ------------------------------------------------------------------------- */
00002 /* file acq2xx_server.cpp                                                    */
00003 /* ------------------------------------------------------------------------- */
00004 /*   Copyright (C) 2006 Peter Milne, D-TACQ Solutions Ltd
00005  *                      <Peter dot Milne at D hyphen TACQ dot com>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of Version 2 of the GNU General Public License
00009     as published by the Free Software Foundation;
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
00019 /* ------------------------------------------------------------------------- */
00020 
00021 /** @file acq2xx_server.cpp server WS implementation.
00022  *
00023  * usage: acq2xx_server [port]
00024  *
00025  * Server is multi-threaded, and stays resident by default
00026  */
00027 #include "soapH.h"
00028 #include "acq2xx.nsmap"
00029 
00030 #ifdef __arm
00031 #include "local.h"
00032 #else
00033 #include <stdio.h>
00034 #endif
00035 
00036 #ifndef __arm
00037 #define info    printf
00038 #endif
00039 #define MAXBUF 16384
00040 
00041 using namespace std;
00042 
00043 #include <assert.h>
00044 #include <iostream>
00045 #include <iomanip>
00046 #include <string>
00047 
00048 #define ACQCMD "/usr/local/bin/acqcmd"
00049 
00050 #define NOT_FOR_SERVER  0
00051 
00052 static int verbose = 0;
00053 static int logcommands = 0;
00054 
00055 #include <string.h>
00056 
00057 
00058 class Actor {
00059 public:
00060         virtual ~Actor() {}
00061         virtual int spawn_read(char* lcommand, char* buf, int maxbuf);
00062 };
00063 
00064 class ActorStub : public Actor {
00065 public:
00066         virtual int spawn_read(char* lcommand, char* buf, int maxbuf);  
00067 };
00068 
00069 
00070 static Actor* actor = new Actor();
00071 
00072 
00073 #include "soapH.h"
00074 #include <pthread.h>
00075 #define BACKLOG (100) // Max. request backlog
00076 #define MAX_THR (10) // Max. threads to serve requests
00077 
00078 static int cgi_main(soap* soap);
00079 static int standalone_main(soap* soap, int port);
00080 
00081 int main(int argc, char **argv)
00082 {
00083         struct soap soap;
00084         soap_init(&soap);
00085 
00086 #ifdef __arm
00087         info("acq2xx_server $Revision: 1.23 $ " ACQ2XX_H_VERSION);
00088 #endif
00089         if (getenv("ACQ2XX_SERVER_STUB")){
00090                 actor = new ActorStub();               
00091         }
00092         if (getenv("ACQ2XX_LOG")){
00093                 logcommands = atoi(getenv("ACQ2XX_LOG"));
00094                 info("ACQ2XX_LOG set logcommands %d", logcommands);
00095         }
00096         if (getenv("ACQ2XX_WS_VERBOSE")){
00097                 verbose = atoi(getenv("ACQ2XX_WS_VERBOSE"));
00098                 info("ACQ2XX_WS_VERBOSE set verbose %d", verbose);
00099         }
00100 
00101         
00102         if (argc < 2){
00103                 return cgi_main(&soap);
00104         }else{
00105                 return standalone_main(&soap, atoi(argv[1]));
00106         }
00107 }
00108 
00109 
00110 static int cgi_main(soap* soap)
00111 {
00112         soap_serve(soap); // serve request, one thread, CGI style
00113         soap_destroy(soap); // dealloc C++ data
00114         soap_end(soap); // dealloc data and clean up
00115         return 0;
00116 }
00117 
00118 static void print_signon(soap* soap, int i, int s)
00119 {
00120 #ifdef __arm
00121         info(
00122 #else
00123         fprintf(stderr, 
00124 #endif
00125                 "Thread %d accepts socket %d connection from IP %d.%d.%d.%d\n", 
00126                 i, s, (soap->ip >> 24)&0xFF, (soap->ip >> 16)&0xFF, 
00127                 (soap->ip >> 8)&0xFF, soap->ip&0xFF);
00128 }
00129 
00130 
00131 static int standalone_main(soap* soap, int port)
00132 {
00133         // each thread needs a runtime environment
00134         struct soap *soap_thr[MAX_THR]; 
00135         pthread_t tid[MAX_THR];
00136         SOAP_SOCKET m, s;
00137         int i;
00138 
00139         m = soap_bind(soap, NULL, port, BACKLOG);
00140         if (!soap_valid_socket(m)){
00141                 exit(1);
00142         }
00143         fprintf(stderr, "Socket connection successful %d\n", m);
00144         for (i = 0; i < MAX_THR; i++){
00145                 soap_thr[i] = NULL;
00146         }
00147         for (;;){
00148                 for (i = 0; i < MAX_THR; i++){
00149                         s = soap_accept(soap);
00150                         if (!soap_valid_socket(s)){
00151                                 if (soap->errnum){
00152                                         soap_print_fault(soap, stderr);
00153                                         continue; // retry
00154                                 }else{
00155 #ifdef __arm
00156                                         err(
00157 #else
00158                                         fprintf(stderr, 
00159 #endif
00160                                                         "Server timed out\n");
00161                                         break;
00162                                 }
00163                         }
00164                         print_signon(soap, i, s);
00165 
00166                         if (!soap_thr[i]){ // first time around
00167                                 soap_thr[i] = soap_copy(soap);
00168                                 if (!soap_thr[i]){
00169                                         exit(1); // could not allocate
00170                                 }
00171                         }else{  // recycle soap environment
00172                                 pthread_join(tid[i], NULL);
00173 #ifdef __arm
00174                                 info(
00175 #else
00176                                 fprintf(stderr, 
00177 #endif       
00178                                                 "Thread %d completed\n", i);
00179                                 // deallocate C++ data of old thread
00180                                 soap_destroy(soap_thr[i]); 
00181                                 // deallocate data of old thread
00182                                 soap_end(soap_thr[i]); 
00183                         }
00184                         soap_thr[i]->socket = s; // new socket fd
00185                         pthread_create(
00186                                 &tid[i], NULL, (void*(*)(void*))soap_serve, 
00187                                 (void*)soap_thr[i]);
00188                 }
00189         }
00190         for (i = 0; i < MAX_THR; i++){
00191                 if (soap_thr[i]){
00192                         soap_done(soap_thr[i]); // detach context
00193                         free(soap_thr[i]); // free up
00194                 }
00195         }
00196 
00197         return 0;
00198 }
00199 
00200 
00201 int Actor::spawn_read(char* lcommand, char* buf, int maxbuf)
00202 {
00203         if (logcommands){
00204                 info("cmd:%s", lcommand);
00205         }
00206         FILE* fp = popen(lcommand, "r");
00207 
00208         buf[0] = '\0';
00209 
00210         for (char* bp = buf; bp - buf < MAXBUF; ){
00211                 char *nl = fgets(bp, 256, fp);
00212                 if (nl){
00213                         bp += strlen(nl);
00214                 }else{
00215                         break;
00216                 }
00217         }
00218         int rc = pclose(fp);    
00219 
00220         if (logcommands > 1){
00221                 info("[%d] %s", rc, buf);
00222         }
00223 
00224         return rc;
00225 }
00226 
00227 int ActorStub::spawn_read(char* lcommand, char* buf, int maxbuf)
00228 {
00229         char *stubcommand = new char[strlen(lcommand)+10];
00230         
00231         cout << lcommand << endl;
00232 
00233         sprintf(stubcommand, "echo %s", lcommand);
00234         return Actor::spawn_read(stubcommand, buf, maxbuf);
00235 }
00236 
00237 
00238 static int soap_command(
00239         struct soap* soap, char* lcommand, char* command, char*& response)
00240 {
00241         char* buf = (char*)soap_malloc(soap, MAXBUF);
00242         
00243         sprintf(buf, "%s \'%s\'", lcommand, command);
00244         
00245         actor->spawn_read(buf, buf, MAXBUF);
00246 
00247         response = buf;
00248         return SOAP_OK;
00249 }
00250 
00251 
00252 int acq2xx__acqcmd(struct soap *soap, char* command, char*& response)
00253 {
00254         return soap_command(soap, ACQCMD, command, response);
00255 }
00256 
00257 int acq2xx__acq2sh(struct soap *soap, char* command, char*& response)
00258 {
00259         return soap_command(soap, "sh -c", command, response);
00260 }
00261 
00262 int acq2xx__getVersion(
00263         struct soap *soap, 
00264         char* client_version, 
00265         char*& server_version)
00266 {
00267         char* buf = (char*)soap_malloc(soap, strlen(ACQ2XX_H_VERSION)+1);
00268 
00269         strcpy(buf, ACQ2XX_H_VERSION);
00270         server_version = buf;
00271 
00272         if (strcmp(client_version, server_version) != 0){
00273                 info("WARNING: version mismatch client: %s server %s",
00274                      client_version, server_version);
00275         }
00276 
00277         return SOAP_OK;
00278 }
00279 
00280 static int acqcmd(const char* command, char* buf, int maxbuf)
00281 {
00282         char lcommand[128];
00283         
00284         sprintf(lcommand, "%s \'%s\'", ACQCMD, command);
00285         actor->spawn_read(lcommand, buf, maxbuf);
00286         return 0;
00287 }
00288 
00289 int acq2xx__getAcqStatus(struct soap *soap, struct acq2xx__AcqStatus& status)
00290 {
00291         char buf[256];
00292         acq2xx__AcqStatus lbuf;
00293         char* state_string = (char*)soap_malloc(soap, 32);
00294         lbuf.nchan = 5;
00295         lbuf.state_string = "Hello World";
00296 
00297         acqcmd("getNumSamples", buf, 256);
00298         sscanf(buf, "ACQ32:getNumSamples=%d pre=%d post=%d elapsed=%d",
00299                &lbuf.numsamples, &lbuf.prelen, 
00300                &lbuf.postlen, &lbuf.elapsed);
00301         
00302         acqcmd("getState", buf, 256);
00303         sscanf(buf, "ACQ32:%d %s", &lbuf.state, state_string);
00304         lbuf.state_string = state_string;
00305 
00306         acqcmd("getNumChannels", buf, 256);
00307         sscanf(buf, "ACQ32:getNumChannels=%d", &lbuf.nchan);
00308         status = lbuf;
00309 
00310 
00311         return SOAP_OK;
00312 }
00313 
00314 
00315 int acq2xx__setArm(
00316         struct soap* soap, 
00317         int block, 
00318         struct acq2xx__AcqStatus& status)
00319 {
00320         char buf[256];
00321 
00322         acqcmd("setArm", buf, 256);
00323 
00324         if (block){
00325                 acq2xx__AcqStatus lbuf;
00326                 int scanned;
00327 
00328                 do{
00329                         acqcmd("getState", buf, 256);
00330                         scanned = sscanf(buf, "ACQ32:%d", &lbuf.state);
00331                 } while(scanned == 1 && lbuf.state != ST_STOP);
00332                 
00333         }
00334 
00335         return acq2xx__getAcqStatus(soap, status);
00336 }
00337 
00338 
00339 int acq2xx__waitStop(
00340         struct soap* soap, 
00341         int timeout_sec, 
00342         struct acq2xx__AcqStatus& status)
00343 {
00344         if (timeout_sec < 1) timeout_sec = 1;
00345         if (timeout_sec > 10) timeout_sec = 10;
00346 
00347         char command[80];
00348         char buf[80];   
00349         buf[0] = '\0';
00350         
00351         sprintf(command, "acqcmd -t %d --until ST_STOP", timeout_sec);
00352 
00353         actor->spawn_read(command, buf, 80);
00354         return acq2xx__getAcqStatus(soap, status);                      
00355 }
00356 
00357 
00358 static const char* toString(enum acq2xx__DIx dix)
00359 {
00360         switch(dix){
00361         case DI0:       
00362                 return "DI0";
00363         case DI1:
00364                 return "DI1";
00365         case DI2:
00366                 return "DI2";
00367         case DI3:
00368                 return "DI3";
00369         case DI4:
00370                 return "DI4";
00371         case DI5:
00372                 return "DI5";
00373         case DI_NONE:
00374         default:
00375                 return "none";
00376         }
00377 }
00378 
00379 static const char* toString(enum acq2xx__DOx dox)
00380 {
00381         switch(dox){
00382         case DO0:       
00383                 return "DO0";
00384         case DO1:
00385                 return "DO1";
00386         case DO2:
00387                 return "DO2";
00388         case DO3:
00389                 return "DO3";
00390         case DO4:
00391                 return "DO4";
00392         case DO5:
00393                 return "DO5";
00394         case DO_NONE:
00395         default:
00396                 return "none";
00397         }
00398 }
00399 
00400 static const char* toString(enum acq2xx__EDGE edge){
00401         return edge==EDGE_FALLING? "falling": "rising";
00402 }
00403 
00404 
00405 
00406 int acq2xx__acq2script(
00407         struct soap* soap,
00408         acq2xx__Transaction *in, 
00409         struct acq2xx__acq2scriptResponse &result)
00410 {
00411         if (in == 0){
00412                 cerr << "ERROR: null transaction" << endl;
00413                 return -1;
00414         }
00415 
00416         in->exec(soap);
00417         result.out = in;
00418         if (verbose){
00419                 cout << "acq2xx__acq2script" << " output: "; result.out->print();
00420         }
00421         return SOAP_OK;
00422 }
00423 
00424 
00425 
00426 void acq2xx__Transaction::exec(soap *soap)
00427 {
00428         status = run(soap);
00429         complete = 1;
00430 
00431         if (verbose > 1){
00432                 cout << "exec() done complete: " << complete 
00433                      << "status: " <<status ; print();
00434         }
00435 }
00436 
00437 int acq2xx__Transaction::run(soap *soap)
00438 {
00439         cout << "Transaction::run";  print();
00440         return 37;
00441 }
00442 
00443 
00444 
00445 
00446 int acq2xx__TransactionList::run(soap *soap)
00447 {
00448         for (int i = 0; i < __size; i++){
00449                 acq2xx__Transaction* t = __ptr[i];
00450 
00451                 t->exec(soap);
00452                 if (t->status != 0 && t->abort_on_error){
00453                         return t->status;
00454                 }
00455         }
00456 
00457         return 0;
00458 }
00459 
00460 
00461 
00462 
00463 int acq2xx__ShellTransaction::run(soap *soap)
00464 {
00465 
00466         char* buf = (char*)malloc(MAXBUF);      
00467         buf[0] = '\0';
00468         int rc = actor->spawn_read(command, buf, MAXBUF);
00469         
00470         char *_result = (char*)soap_malloc(soap, strlen(buf)+1);
00471         strcpy(_result, buf);
00472         result = _result;
00473 
00474         if (verbose > 1){
00475                 cout << "acq2xx__ShellTransaction::run() command:" << command << endl <<
00476                         "result:" << result << " rc:" << rc << endl;
00477         }
00478 
00479         free(buf);
00480         return rc;      
00481 }
00482 
00483 
00484 acq2xx__ModeSetTransaction::acq2xx__ModeSetTransaction(
00485         enum acq2xx__MODE mode,
00486         int prelen,
00487         int postlen             
00488         )
00489 {
00490         assert(NOT_FOR_SERVER);
00491 }
00492 
00493 int acq2xx__ModeSetTransaction::run(struct soap* soap)
00494 {
00495         char _command[80];
00496 
00497         cout << 
00498         "acq2xx__ModeSetTransaction::run() "<< endl <<
00499                 "mode:" << mode << " pre:" << prelen << 
00500                 " post:" <<  postlen << endl;   
00501 
00502         switch(mode){
00503         case MODE_SOFT_TRANSIENT:
00504         case MODE_SOFT_CONTINUOUS:
00505                 sprintf(_command, "acqcmd setMode %s %d",
00506                         mode==MODE_SOFT_TRANSIENT?
00507                         "SOFT_TRANSIENT": "SOFT_CONTINUOUS",
00508                         mode==MODE_SOFT_TRANSIENT? postlen: prelen);
00509                 break;
00510         case MODE_GATED_TRANSIENT:
00511                 sprintf(_command, "acqcmd setMode GATED_TRANSIENT %d",
00512                         postlen);
00513                 break;
00514         case MODE_TRIGGERED_CONTINUOUS:
00515                 sprintf(_command, "acqcmd setModeTriggeredContinuous %d %d",
00516                         prelen, postlen);                       
00517                 break;
00518         default:
00519                 assert(0);
00520         }
00521 
00522 
00523         initCommand(_command);
00524 
00525         if (verbose > 1){
00526                 cout << "acq2xx__ModeSetTransaction::run() "<<
00527                         _command << endl <<
00528                         "command:" << command << endl;
00529         }
00530 
00531         return acq2xx__ShellTransaction::run(soap);
00532 }
00533 
00534 
00535 acq2xx__ClockSetTransaction::acq2xx__ClockSetTransaction(char *command) :
00536         acq2xx__ShellTransaction(command)
00537 {
00538         assert(NOT_FOR_SERVER);
00539 }
00540 
00541 acq2xx__InternalClockSetTransaction::acq2xx__InternalClockSetTransaction(
00542         int _hz,
00543         int div,
00544         enum acq2xx__DOx dox)
00545 {
00546         assert(NOT_FOR_SERVER);
00547 }
00548 
00549 int acq2xx__InternalClockSetTransaction::run(struct soap* soap)
00550 {
00551         char _command[80];
00552         int cursor = sprintf(_command, "acqcmd setInternalClock %d", hz);
00553         if (div > 1 || dox != DO_NONE){
00554                 cursor += sprintf(_command+cursor, " %d", div);
00555 
00556                 if (dox != DO_NONE){
00557                         cursor += sprintf(_command+cursor, " %s", 
00558                                                         toString(dox));
00559                 }
00560         }
00561         initCommand(_command);
00562         return acq2xx__ClockSetTransaction::run(soap);
00563 }
00564 
00565 acq2xx__ExternalClockSetTransaction::acq2xx__ExternalClockSetTransaction(
00566         enum acq2xx__DIx dix,
00567         int div,
00568         enum acq2xx__DOx dox
00569         )
00570 {
00571         assert(NOT_FOR_SERVER);
00572 }
00573 
00574 int acq2xx__ExternalClockSetTransaction::run(struct soap* soap)
00575 {
00576         char _command[80];
00577         
00578         int cursor = sprintf(_command, "acqcmd setExternalClock %s", 
00579                                 toString(dix));
00580         if (div > 1 || dox != DO_NONE){
00581                 cursor += sprintf(_command+cursor, " %d", div);
00582 
00583                 if (dox != DO_NONE){
00584                         cursor += sprintf(_command+cursor, " %s", 
00585                                                         toString(dox));
00586                 }
00587         }
00588         initCommand(_command);
00589         return acq2xx__ClockSetTransaction::run(soap);
00590 }
00591 
00592 acq2xx__SignalSetTransaction::acq2xx__SignalSetTransaction(
00593         char *name,
00594         enum acq2xx__DIx dix,
00595         enum acq2xx__EDGE edge)
00596 {
00597         assert(NOT_FOR_SERVER);
00598 }
00599 
00600 int acq2xx__SignalSetTransaction::run(soap* soap)
00601 {
00602         char command[80];
00603         sprintf(command, "set.%s %s %s", signal, 
00604                         toString(dix), dix != DI_NONE? toString(edge): "");
00605         initCommand(command);
00606         return acq2xx__ShellTransaction::run(soap);
00607 }
00608 
00609 acq2xx__AcqControlTransaction::acq2xx__AcqControlTransaction(
00610         acq2xx__ModeSetTransaction* _modeSet,
00611         acq2xx__ClockSetTransaction* _clockSet,
00612         acq2xx__SignalSetTransaction* _trigger,
00613         acq2xx__SignalSetTransaction* _event0
00614         )
00615 {
00616         assert(NOT_FOR_SERVER);
00617 }
00618 
00619 acq2xx__AcqControlTransaction::acq2xx__AcqControlTransaction()
00620 {
00621 }
00622 
00623 int acq2xx__GetAvailableChannelsTransaction::run(soap* soap)
00624 {
00625         int rc = acq2xx__ShellTransaction::run(soap);
00626         if (rc == 0){
00627                 return sscanf(result, 
00628                                 "ACQ32:getAvailableChannels AI=%d AO=%d",
00629                               &AI, &AO) != 2;
00630         }else{
00631                 return rc;
00632         }
00633 }
00634 
00635 
00636 static int parseVR(VRange* ranges, int channels, char* result)
00637 {
00638         char *rbuf = (char*)malloc(strlen(result)+1);
00639 
00640         strcpy(rbuf, result);
00641         char *str = rbuf;
00642         char *tok;
00643 
00644         for (int ic = 0; ic < channels; ++ic){
00645                 if ((tok = strtok(str, ","))){
00646                         ranges[ic].min = atof(tok);
00647                 }else{
00648                         return -1;
00649                 }
00650                 str = 0;
00651                 if ((tok = strtok(str, ","))){
00652                         ranges[ic].max = atof(tok);
00653                 }else{
00654                         return -1;
00655                 }               
00656         }
00657         free(rbuf);
00658         return 0;
00659 }
00660 int acq2xx__GetVRangeTransaction::run(soap* soap)
00661 {
00662         channels = soap_new_acq2xx__GetAvailableChannelsTransaction(soap, -1);
00663 
00664         int rc = channels->run(soap);
00665         if (rc == 0){
00666                 rc = acq2xx__ShellTransaction::run(soap);
00667                 if (rc == 0){
00668                         ranges.__ptr = soap_new_VRange(soap, channels->AI);
00669                         ranges.__size = channels->AI;
00670                         return parseVR(ranges.__ptr, channels->AI, result);
00671                 }
00672         }
00673 
00674         return rc;
00675 }

Generated on Mon Aug 21 12:39:57 2006 for ACQ2XXWebServices by  doxygen 1.4.4