apps/web/imgsrv/imgsrv.c

Go to the documentation of this file.
00001 /*!***************************************************************************
00002 *! FILE NAME  : imgsrv.c
00003 *! DESCRIPTION: Simple and fast HTTP server to send camera still images
00004 *! Copyright (C) 2007-2008 Elphel, Inc.
00005 *! -----------------------------------------------------------------------------**
00006 *!  This program is free software: you can redistribute it and/or modify
00007 *!  it under the terms of the GNU General Public License as published by
00008 *!  the Free Software Foundation, either version 3 of the License, or
00009 *!  (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
00018 *! -----------------------------------------------------------------------------**
00019 *!
00020 *!  $Log: imgsrv.c,v $
00021 *!  Revision 1.1.1.1  2008/11/27 20:04:01  elphel
00022 *!
00023 *!
00024 *!  Revision 1.11  2008/11/03 18:42:21  elphel
00025 *!  comment typo
00026 *!
00027 *!  Revision 1.10  2008/10/29 04:18:28  elphel
00028 *!  v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
00029 *!
00030 *!  Revision 1.9  2008/10/25 19:51:40  elphel
00031 *!  updated copyright year
00032 *!
00033 *!  Revision 1.8  2008/10/21 21:28:52  elphel
00034 *!  support for xml meta output
00035 *!
00036 *!  Revision 1.7  2008/10/13 16:55:53  elphel
00037 *!  removed (some) obsolete P_* parameters, renamed CIRCLSEEK to LSEEK_CIRC constants (same as other similar)
00038 *!
00039 *!  Revision 1.6  2008/10/11 18:46:07  elphel
00040 *!  snapshot
00041 *!
00042 *!  Revision 1.5  2008/10/06 08:31:08  elphel
00043 *!  snapshot, first images
00044 *!
00045 *!  Revision 1.4  2008/09/07 19:48:08  elphel
00046 *!  snapshot
00047 *!
00048 *!  Revision 1.3  2008/08/11 19:10:45  elphel
00049 *!  reduced syntax "complaints" from KDevelop
00050 *!
00051 *!  Revision 1.2  2008/05/16 06:06:54  elphel
00052 *!  supporting variable JPEG header length
00053 *!
00054 *!  Revision 1.14  2008/04/22 22:14:56  elphel
00055 *!  Added malloc failures handling, syslog logging of such events
00056 *!
00057 *!  Revision 1.13  2008/04/16 20:30:33  elphel
00058 *!  added optional fps reduction to multipart JPEGs
00059 *!
00060 *!  Revision 1.11  2008/04/07 09:13:35  elphel
00061 *!  Changes related to new Exif generation/processing
00062 *!
00063 *!  Revision 1.10  2008/03/22 04:39:53  elphel
00064 *!  remove complaints about "&_time=..."
00065 *!
00066 *!  Revision 1.9  2007/12/03 08:28:45  elphel
00067 *!  Multiple changes, mostly cleanup
00068 *!
00069 *!  Revision 1.8  2007/11/16 08:56:19  elphel
00070 *!  Added support for 2 additional commands to check circbuf usage
00071 *!
00072 *!  Revision 1.7  2007/11/04 23:25:16  elphel
00073 *!  removed extra (used during debug) munmap that caused segfault after sending "img" (so no /nxt/save)
00074 *!
00075 *!  Revision 1.6  2007/11/04 05:47:40  elphel
00076 *!  Cleaned up from debug code inserted to fight mmap/caching bug (fixed by now)
00077 *!
00078 *!  Revision 1.5  2007/11/01 18:59:37  elphel
00079 *!  debugging mmap/caching problems
00080 *!
00081 *!  Revision 1.4  2007/10/30 16:56:06  elphel
00082 *!  release 7.1.4.5 - working on "can not find 0xffff in frame parameters" bug. Temporary fix
00083 *!
00084 *!  Revision 1.3  2007/10/27 00:55:32  elphel
00085 *!  untested revision - need to go
00086 *!
00087 *!  Revision 1.2  2007/10/11 06:42:28  elphel
00088 *!  Fixed bug - /meta command should return trivial xml file, not 1x1 pixel gif
00089 *!
00090 *!  Revision 1.1.1.1  2007/10/02 19:44:54  elphel
00091 *!  This is a fresh tree based on elphel353-2.10
00092 *!
00093 *!  Revision 1.4  2007/10/02 19:44:54  elphel
00094 *!  More functionality (buffer manipulation commands, clean interface, xml responces)
00095 *!
00096 *!  Revision 1.3  2007/09/29 16:21:25  elphel
00097 *!  removed IOCTL usage from /dev/circbuf, improved comments, other minor changes
00098 *!
00099 *!  Revision 1.2  2007/09/25 23:35:16  elphel
00100 *!  added Exif initialization, made it to work in background mode
00101 *!
00102 *!  Revision 1.1  2007/09/23 06:49:10  elphel
00103 *!  Simple web server designed for particular task - serving camera JPEG images. It is faster, than through any of the web servers tested. Only some of the functionality is implemented (no Exif yet, no synchronization with the camera)
00104 *!
00105 *!
00106 */ 
00107 #include <unistd.h>
00108 #include <stdio.h>
00109 #include <stdlib.h>
00110 #include <signal.h>
00111 #include <fcntl.h>
00112 #include <errno.h>
00113 #include <sys/types.h>
00114 #include <sys/socket.h>
00115 #include <sys/stat.h>
00116 //#include <ctype.h>
00117 //#include <getopt.h>
00118 #include <time.h>
00119 #include <string.h>
00120 #include <syslog.h>
00121 
00122 #include <netinet/in.h>
00123 #include <sys/mman.h>           /* mmap */
00124 #include <sys/ioctl.h>
00125 
00126 #include <asm/elphel/c313a.h>
00127 #include <asm/elphel/exifa.h>
00128 #include <asm/elphel/ext353.h>
00129 #include <asm/byteorder.h>
00130 
00131 #if ELPHEL_DEBUG
00132   #define ELPHEL_DEBUG_THIS 0
00133 #else
00134   #define ELPHEL_DEBUG_THIS 0
00135 #endif
00136 
00137 
00138 #if ELPHEL_DEBUG_THIS
00139   #define D(x) fprintf(stderr,"%s:%d:%s: ",__FILE__,__LINE__,__FUNCTION__);x
00140 #else
00141   #define D(x)
00142 #endif
00143 
00144 //#define USEHTTP10(x)
00145 #define USEHTTP10(x) x
00146 
00147 // HEADER_SIZE is defined to be larger than actual header (later - with EXIF)  to use compile-time buffer
00148 //#define JPEG_HEADER_SIZE    0x26f // will not change
00149 #define JPEG_HEADER_MAXSIZE    0x300 // will not change
00150 
00151 #define TRAILER_SIZE   0x02
00152 #define MAP_OPTIONS MAP_FILE|MAP_PRIVATE
00153 //#define GLOBALPARS(x) globalPars[(x)-FRAMEPAR_GLOBALS] // should work in drivers and application
00154 unsigned long * ccam_dma_buf;           /* mmapped array */
00155 
00156 char trailer[TRAILER_SIZE] = {0xff,0xd9};
00157 
00158 
00159 const char url_args[]="This server supports sequence of commands entered in the URL (separated by \"/\", case sensitive )\n"
00160                       "executing them from left to right as they appear in the URL\n"
00161                       "img -      send image at the current pointer (if it is first command - use last acquired image, if none availabe - send 1x1 gif)\n"
00162                       "bimg -     same as above, but save the whole image in the memory before sending - useful to avoid overruns with slow connection \n"
00163                       "mimg[n] -  send images as a multipart JPEG (all commands after will be ignored), possible to specify optional fps reduction\n"
00164                       "           i.e. mimg4 - skip 3 frames for each frame output (1/4 fps) \n"
00165                       "bmimg[n] - same as above, buffered\n"
00166                       "pointers - send XML-formatted data about frames available in the camera circular buffer)\n\n"
00167                       "Any of the 5 commands above can appear only once in the URL string, the second instance will be ignored. If none of the 5\n"
00168                       "are present in the URL 1x1 pixel gif will be returned to the client after executing the URL command.\n\n"
00169                       "torp -   set frame pointer to global read pointer, maintained by the camera driver. If frame at that pointer\n"
00170                       "         is invalid, use scnd (see below)\n"
00171                       "towp -   set frame pointer to hardware write pointer - position where next frame will be aquired\n"
00172                       "prev -   move to previous frame in buffer, nop if there are none\n"
00173                       "next -   move to the next frame in buffer (will stop at write pointer, see towp above)\n"
00174                       "last -   move to the most recently acquired frame, or to write pointer if there are none.\n"
00175                       "         this command is implied at the start of the url command sequence.\n"
00176                       "first -  move to the oldest frame still available in the buffer. It is not safe to rely on it if\n"
00177                       "         more frames are expected - data might be overwritten at any moment and the output will be corrupted.\n"
00178                       "second - move to the second oldest frame in the buffer - somewhat safer than \"first\" - there will be time for\n"
00179                       "         \"next\" command at least before frame data (and pointer structures) will be overwritten.\n"
00180                       "save   - save current frame pointer as a global read pointer that holds it values between server requests.\n"
00181                       "         This pointer is shared between all the clients and applications that use it.\n"
00182                       "wait   - Wait until there will be a frame at current pointer ready\n";
00183 int  sendImage (int bufferImageData, int fd_circ, int use_Exif);
00184 void sendBuffer(void * buffer, int len);
00185 void listener_loop(int port);
00186 void errorMsgXML(char * msg);
00187 int  framePointersXML(int fd_circ);
00188 int  metaXML(int fd_circ, int mode); 
00189 int  printExifXML(int exif_page);
00190 
00191 int  out1x1gif(void);
00192 
00193 
00194 #define saferead255(f,d,l) read(f,d,((l)<256)?(l):255)
00195 int printExifXML(int exif_page) {
00196      int indx;
00197      long numfields=0;
00198      struct exif_dir_table_t dir_table_entry;
00199      int fd_exifdir;
00200      struct exif_dir_table_t exif_dir[ExifKmlNumber] ;  
00201 
00202 
00203      fd_exifdir = open(EXIFDIR_DEV_NAME, O_RDONLY);
00204      if (fd_exifdir <0) {
00205        printf ("<error>\"Opening %s\"</error>\n",EXIFDIR_DEV_NAME);
00206        return -2 ; 
00207      }
00208      for (indx=0; indx<ExifKmlNumber; indx++) exif_dir[indx].ltag=0;
00209      while (read(fd_exifdir, &dir_table_entry, sizeof(dir_table_entry))>0) {
00210        switch (dir_table_entry.ltag) {
00211          case Exif_Image_ImageDescription:      indx= Exif_Image_ImageDescription_Index; break;
00212          case Exif_Image_FrameNumber:           indx= Exif_Image_FrameNumber_Index; break;
00213          case Exif_Photo_DateTimeOriginal:      indx= Exif_Photo_DateTimeOriginal_Index; break;
00214          case Exif_Photo_SubSecTimeOriginal:    indx= Exif_Photo_SubSecTimeOriginal_Index; break;
00215          case Exif_Photo_ExposureTime:          indx= Exif_Photo_ExposureTime_Index; break;
00216          case Exif_GPSInfo_GPSLatitudeRef:      indx= Exif_GPSInfo_GPSLatitudeRef_Index; break;
00217          case Exif_GPSInfo_GPSLatitude:         indx= Exif_GPSInfo_GPSLatitude_Index ; break;
00218          case Exif_GPSInfo_GPSLongitudeRef:     indx= Exif_GPSInfo_GPSLongitudeRef_Index ; break;
00219          case Exif_GPSInfo_GPSLongitude:        indx= Exif_GPSInfo_GPSLongitude_Index; break;
00220          case Exif_GPSInfo_GPSAltitudeRef:      indx= Exif_GPSInfo_GPSAltitudeRef_Index; break;
00221          case Exif_GPSInfo_GPSAltitude:         indx= Exif_GPSInfo_GPSAltitude_Index; break;
00222          case Exif_GPSInfo_GPSTimeStamp:        indx= Exif_GPSInfo_GPSTimeStamp_Index; break;
00223          case Exif_GPSInfo_GPSDateStamp:        indx= Exif_GPSInfo_GPSDateStamp_Index; break;
00224          case Exif_GPSInfo_GPSMeasureMode:      indx= Exif_GPSInfo_GPSMeasureMode_Index; break;
00225          case Exif_GPSInfo_CompassDirectionRef: indx= Exif_GPSInfo_CompassDirectionRef_Index; break;
00226          case Exif_GPSInfo_CompassDirection:    indx= Exif_GPSInfo_CompassDirection_Index; break;
00227          case Exif_GPSInfo_CompassPitchRef:     indx= Exif_GPSInfo_CompassPitchRef_Index; break;
00228          case Exif_GPSInfo_CompassPitch:        indx= Exif_GPSInfo_CompassPitch_Index; break;
00229          case Exif_GPSInfo_CompassRollRef:      indx= Exif_GPSInfo_CompassRollRef_Index; break;
00230          case Exif_GPSInfo_CompassRoll:         indx= Exif_GPSInfo_CompassRoll_Index; break;
00231          default: indx=-1;
00232        }
00233        if (indx>=0) {
00234            memcpy(&(exif_dir[indx]),&dir_table_entry,sizeof(dir_table_entry));
00235            numfields++;
00236        }
00237      }
00238      close (fd_exifdir);
00240 
00241      long rational3[6];
00242      long exif_page_start;
00243      char val[256];
00244      int hours=0, minutes=0;
00245      double seconds=0.0;
00246      double  longitude=0.0, latitude=0.0,  altitude=0.0,  heading=0.0,  roll=0.0, pitch=0.0, exposure=0.0;
00247      val[255]='\0';
00248      int fd_exif= open(EXIF_DEV_NAME, O_RDONLY);
00249      if (fd_exif <0) {
00250        printf ("<error>\"Opening %s\"</error>\n",EXIF_DEV_NAME);
00251        return -3 ;
00252      }
00253      exif_page_start= lseek (fd_exif, exif_page, SEEK_END); 
00254      if (exif_page_start<0) {
00255        printf ("<error>\"Exif page (%d) is out of range\"</error>\n",exif_page);
00256        close (fd_exif);
00257        return -1 ; 
00258      }
00260      if (exif_dir[Exif_Image_ImageDescription_Index].ltag==Exif_Image_ImageDescription) { // Exif_Image_ImageDescription is present in template
00261        lseek (fd_exif,
00262               exif_page_start+exif_dir[Exif_Image_ImageDescription_Index].dst,
00263               SEEK_SET);
00264        saferead255(fd_exif, val, exif_dir[Exif_Image_ImageDescription_Index].len);
00265        printf("<ImageDescription>\"%s\"</ImageDescription>\n",val);
00266      }
00268      if (exif_dir[Exif_Image_FrameNumber_Index].ltag==Exif_Image_FrameNumber) { // Exif_Image_FrameNumber_Index is present in template
00269        lseek (fd_exif,
00270               exif_page_start+exif_dir[Exif_Image_FrameNumber_Index].dst,
00271               SEEK_SET);
00272        read(fd_exif, rational3, 4);
00273        sprintf (val,"%ld", (long) __cpu_to_be32( rational3[0]));
00274        printf("<FrameNumber>\"%s\"</FrameNumber>\n",val);
00275      }
00276 
00278      if (exif_dir[Exif_Photo_DateTimeOriginal_Index].ltag==Exif_Photo_DateTimeOriginal) {
00279        lseek (fd_exif,
00280               exif_page_start+exif_dir[Exif_Photo_DateTimeOriginal_Index].dst,
00281               SEEK_SET);
00282        read(fd_exif, val, 19);
00283        val[19]='\0';
00284        if (exif_dir[Exif_Photo_SubSecTimeOriginal_Index].ltag==Exif_Photo_SubSecTimeOriginal) {
00285          val[19]='.';
00286          lseek (fd_exif,
00287                 exif_page_start+exif_dir[Exif_Photo_SubSecTimeOriginal_Index].dst,
00288                 SEEK_SET);
00289          read(fd_exif, &val[20], 7);
00290          val[27]='\0';
00291        }
00292        printf("<DateTimeOriginal>\"%s\"</DateTimeOriginal>\n",val);
00293      }
00295      if (exif_dir[Exif_Photo_ExposureTime_Index].ltag==Exif_Photo_ExposureTime) { // Exif_Photo_ExposureTime is present in template
00296        lseek (fd_exif,
00297               exif_page_start+exif_dir[Exif_Photo_ExposureTime_Index].dst,
00298               SEEK_SET);
00299        read(fd_exif, rational3, 8);
00300        exposure=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00301        sprintf (val,"%f",exposure);
00302        printf("<ExposureTime>\"%s\"</ExposureTime>\n",val);
00303      }
00305      if (exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].ltag==Exif_GPSInfo_GPSMeasureMode) {
00306        lseek (fd_exif,
00307               exif_page_start+exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].dst,
00308               SEEK_SET);
00309        read(fd_exif, val, 1);
00310        printf("<GPSMeasureMode>\"%s\"</GPSMeasureMode>\n",val);
00311      }
00313      if (exif_dir[Exif_GPSInfo_GPSDateStamp_Index].ltag==Exif_GPSInfo_GPSDateStamp) {
00314        lseek (fd_exif,
00315               exif_page_start+exif_dir[Exif_GPSInfo_GPSDateStamp_Index].dst,
00316               SEEK_SET);
00317        read(fd_exif, val, 10);
00318        val[10]='\0';
00319        if (exif_dir[Exif_GPSInfo_GPSTimeStamp_Index].ltag==Exif_GPSInfo_GPSTimeStamp) {
00320          lseek (fd_exif,
00321                 exif_page_start+exif_dir[Exif_GPSInfo_GPSTimeStamp_Index].dst,
00322                 SEEK_SET);
00323          read(fd_exif, rational3, 24);
00324          hours=   __cpu_to_be32( rational3[0]);
00325          minutes= __cpu_to_be32( rational3[2]);
00326          seconds= (1.0*(__cpu_to_be32( rational3[4])+1))/__cpu_to_be32( rational3[5]); 
00327          sprintf (&val[10]," %02d:%02d:%05.2f",hours,minutes,seconds);
00328        }
00329        printf("<GPSDateTime>\"%s\"</GPSDateTime>\n",val);
00330      }
00331 
00334      if (exif_dir[Exif_GPSInfo_GPSLongitude_Index].ltag==Exif_GPSInfo_GPSLongitude) { // Exif_GPSInfo_GPSLongitude is present in template
00335        lseek (fd_exif,
00336               exif_page_start+exif_dir[Exif_GPSInfo_GPSLongitude_Index].dst,
00337               SEEK_SET);
00338        read(fd_exif, rational3, 24);
00339        longitude=__cpu_to_be32( rational3[0])/(1.0*__cpu_to_be32( rational3[1])) + __cpu_to_be32( rational3[2])/(60.0*__cpu_to_be32( rational3[3]));
00340        if (exif_dir[Exif_GPSInfo_GPSLongitudeRef_Index].ltag==Exif_GPSInfo_GPSLongitudeRef) {
00341          lseek (fd_exif,
00342             exif_page_start+exif_dir[Exif_GPSInfo_GPSLongitudeRef_Index].dst,
00343             SEEK_SET);
00344          read(fd_exif, val, 1);
00345          if (val[0]!= 'E') longitude=-longitude;
00346        }
00347        sprintf (val,"%f",longitude);
00348        printf("<GPSLongitude>\"%s\"</GPSLongitude>\n",val);
00349      }
00351      if (exif_dir[Exif_GPSInfo_GPSLatitude_Index].ltag==Exif_GPSInfo_GPSLatitude) { // Exif_GPSInfo_GPSLatitude is present in template
00352        lseek (fd_exif,
00353               exif_page_start+exif_dir[Exif_GPSInfo_GPSLatitude_Index].dst,
00354               SEEK_SET);
00355        read(fd_exif, rational3, 24);
00356        latitude=__cpu_to_be32( rational3[0])/(1.0*__cpu_to_be32( rational3[1])) + __cpu_to_be32( rational3[2])/(60.0*__cpu_to_be32( rational3[3]));
00357        if (exif_dir[Exif_GPSInfo_GPSLatitudeRef_Index].ltag==Exif_GPSInfo_GPSLatitudeRef) {
00358          lseek (fd_exif,
00359             exif_page_start+exif_dir[Exif_GPSInfo_GPSLatitudeRef_Index].dst,
00360             SEEK_SET);
00361          read(fd_exif, val, 1);
00362          if (val[0] != 'N') latitude=-latitude;
00363         }
00364        sprintf (val,"%f",latitude);
00365        printf("<GPSLatitude>\"%s\"</GPSLatitude>\n",val);
00366      }
00368      if (exif_dir[Exif_GPSInfo_GPSAltitude_Index].ltag==Exif_GPSInfo_GPSAltitude) { // Exif_GPSInfo_GPSAltitude is present in template
00369        lseek (fd_exif,
00370               exif_page_start+exif_dir[Exif_GPSInfo_GPSAltitude_Index].dst,
00371               SEEK_SET);
00372        read(fd_exif, rational3, 8);
00373        altitude=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00374 
00375        if (exif_dir[Exif_GPSInfo_GPSAltitudeRef_Index].ltag==Exif_GPSInfo_GPSAltitudeRef) {
00376          lseek (fd_exif,
00377             exif_page_start+exif_dir[Exif_GPSInfo_GPSAltitudeRef_Index].dst,
00378             SEEK_SET);
00379          read(fd_exif, val, 1);
00380          if (val[0] != '\0') altitude=-altitude;
00381         }
00382        sprintf (val,"%f",altitude);
00383        printf("<GPSAltitude>\"%s\"</GPSAltitude>\n",val);
00384      }
00386      if (exif_dir[Exif_GPSInfo_CompassDirection_Index].ltag==Exif_GPSInfo_CompassDirection) { // Exif_GPSInfo_CompassDirection is present in template
00387        lseek (fd_exif,
00388               exif_page_start+exif_dir[Exif_GPSInfo_CompassDirection_Index].dst,
00389               SEEK_SET);
00390        read(fd_exif, rational3, 8);
00391        heading=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00392        sprintf (val,"%f",heading);
00393        printf("<CompassDirection>\"%s\"</CompassDirection>\n",val);
00394      }
00397      if (exif_dir[Exif_GPSInfo_CompassRoll_Index].ltag==Exif_GPSInfo_CompassRoll) { // Exif_GPSInfo_CompassRoll is present in template
00398        lseek (fd_exif,
00399               exif_page_start+exif_dir[Exif_GPSInfo_CompassRoll_Index].dst,
00400               SEEK_SET);
00401        read(fd_exif, rational3, 8);
00402        roll=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00403 
00404        if (exif_dir[Exif_GPSInfo_CompassRollRef_Index].ltag==Exif_GPSInfo_CompassRollRef) {
00405          lseek (fd_exif,
00406             exif_page_start+exif_dir[Exif_GPSInfo_CompassRollRef_Index].dst,
00407             SEEK_SET);
00408          read(fd_exif, val, 1);
00409          if (val[0] != EXIF_COMPASS_ROLL_ASCII[0]) roll=-roll;
00410         }
00411        sprintf (val,"%f",roll);
00412        printf("<CompassRoll>\"%s\"</CompassRoll>\n",val);
00413      }
00414 
00416      if (exif_dir[Exif_GPSInfo_CompassPitch_Index].ltag==Exif_GPSInfo_CompassPitch) { // Exif_GPSInfo_CompassPitch is present in template
00417        lseek (fd_exif,
00418               exif_page_start+exif_dir[Exif_GPSInfo_CompassPitch_Index].dst,
00419               SEEK_SET);
00420        read(fd_exif, rational3, 8);
00421        pitch=(1.0*__cpu_to_be32( rational3[0]))/__cpu_to_be32( rational3[1]);
00422 
00423        if (exif_dir[Exif_GPSInfo_CompassPitchRef_Index].ltag==Exif_GPSInfo_CompassPitchRef) {
00424          lseek (fd_exif,
00425             exif_page_start+exif_dir[Exif_GPSInfo_CompassPitchRef_Index].dst,
00426             SEEK_SET);
00427          read(fd_exif, val, 1);
00428          if (val[0] != EXIF_COMPASS_PITCH_ASCII[0]) pitch=-pitch;
00429         }
00430        sprintf (val,"%f",pitch);
00431        printf("<CompassPitch>\"%s\"</CompassPitch>\n",val);
00432      }
00433      close (fd_exif);
00434      return 0;
00435 }
00436 
00437 
00438 
00439 int  metaXML(int fd_circ, int mode) { 
00440    int  frameParamPointer=0;
00441    struct interframe_params_t frame_params;
00442    int jpeg_len,jpeg_start,buff_size,timestamp_start;
00443    if (mode==2) {
00444      printf ("</meta>\n");
00445      return 0;
00446    } else if (mode==0) { 
00447      printf("HTTP/1.0 200 OK\n");
00448      printf("Server: Elphel Imgsrv\n");
00449      printf("Content-Type: text/xml\n");
00450      printf("Pragma: no-cache\n");
00451      printf("\n");
00452      printf ("<?xml version=\"1.0\"?>\n" \
00453              "<meta>\n");
00454    }
00455 
00456    jpeg_start=lseek(fd_circ,0,SEEK_CUR); //get the current read pointer
00457    D(fprintf(stderr,"jpeg_start= (long)=0x%x\n",jpeg_start>>2));
00458    if (jpeg_start <0 ) {
00459      printf("<error>\"No frame at the current pointer\"</error>\n");
00460      return -1;
00461    }
00462    buff_size=lseek(fd_circ,0,SEEK_END);
00464    lseek(fd_circ, jpeg_start, SEEK_SET);
00465 
00466    frameParamPointer=jpeg_start-32;
00467    if (frameParamPointer<0) frameParamPointer+=buff_size;
00468    memcpy (&frame_params, (unsigned long * ) &ccam_dma_buf[frameParamPointer>>2],32); 
00469    jpeg_len=frame_params.frame_length;
00471    timestamp_start=jpeg_start+((jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; 
00472    if (timestamp_start >= buff_size) timestamp_start-=buff_size;
00473    memcpy (&(frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
00475    printf ("<frame>\n" \
00476               "<start>    0x%x </start>\n" \
00477               "<hash32_r> 0x%x </hash32_r>\n" \
00478               "<hash32_g> 0x%x </hash32_g>\n" \
00479               "<hash32_gb>0x%x </hash32_gb>\n" \
00480               "<hash32_b> 0x%x </hash32_b>\n" \
00481               "<quality2> 0x%x </quality2>\n" \
00482               "<color> 0x%x </color>\n" \
00483               "<byrshift> 0x%x </byrshift>\n" \
00484               "<width> 0x%x </width>\n" \
00485               "<height> 0x%x </height>\n" \
00486               "<meta_index> 0x%x </meta_index>\n" \
00487               "<signffff> 0x%x </signffff>\n"
00488            , (int) jpeg_start
00489            , (int) frame_params.hash32_r
00490            , (int) frame_params.hash32_g
00491            , (int) frame_params.hash32_gb
00492            , (int) frame_params.hash32_b
00493            , (int) frame_params.quality2
00494            , (int) frame_params.color          
00495            , (int) frame_params.byrshift       
00496            , (int) frame_params.width          
00497            , (int) frame_params.height         
00498            , (int) frame_params.meta_index     
00499            , (int) frame_params.signffff
00500            );
00501 
00502    if (frame_params.signffff !=0xffff) {
00503      printf("<error>\"wrong signature (should be 0xffff)\"</error>\n");
00504    } else {
00506      printf ("<Exif>\n");
00507      printExifXML(frame_params.meta_index);
00508      printf ("</Exif>\n");
00509    }
00510    printf ("</frame>\n");
00511    return 0;
00512 }
00513 
00514 
00515 int framePointersXML(int fd_circ) {
00516   const char ctlFileName[]="/dev/frameparsall";
00517   int fd_fparmsall;
00518   char s[512]; // 341;
00519   int p, wp, rp;
00520   int nf=0;
00521   int nfl=0;
00522   int buf_free, buf_used;
00523   int save_p; 
00524   int frame8, frame_number, sensor_state, compressor_state;
00525   char *cp_sensor_state, *cp_compressor_state;
00526 
00527   struct framepars_all_t   *frameParsAll;
00528   struct framepars_t       *framePars;
00529   unsigned long            *globalPars;
00530 
00531 
00532     fd_fparmsall = open(ctlFileName, O_RDWR);
00533     if (fd_fparmsall<0) { // check control OK
00534        printf ("Error opening %s\n", ctlFileName);
00535        fprintf(stderr,"%s:%d:%s: Error opening %s\n",__FILE__,__LINE__,__FUNCTION__, ctlFileName);
00536        return -1;
00537     }
00538 
00540     frameParsAll = (struct framepars_all_t *) mmap(0, sizeof (struct framepars_all_t) , PROT_READ, MAP_SHARED, fd_fparmsall, 0);
00541     if((int)frameParsAll == -1) {
00542       frameParsAll=NULL;
00543       printf("Error in mmap /dev/frameparsall");
00544       fprintf(stderr,"%s:%d:%s: Error in mmap in %s\n",__FILE__,__LINE__,__FUNCTION__,ctlFileName);
00545       close (fd_fparmsall);
00546       fd_fparmsall = -1;
00547       return -1;
00548     }
00549     framePars=frameParsAll->framePars;
00550     globalPars=frameParsAll->globalPars;
00551 
00552 // Read current sensor state - defined in c313a.h
00553     frame_number=lseek(fd_fparmsall, 0, SEEK_CUR );
00554     frame8= frame_number & PARS_FRAMES_MASK;
00555 //    printf ("Current frame number is %d\n",frame_number);
00556     sensor_state=framePars[frame8].pars[P_SENSOR_RUN];
00557     compressor_state=framePars[frame8].pars[P_COMPRESSOR_RUN];
00558     cp_sensor_state=     (sensor_state==0)?
00559                              "SENSOR_RUN_STOP":
00560                              ((sensor_state==1)?
00561                                   "SENSOR_RUN_SINGLE":
00562                                   ((sensor_state==2)?"SENSOR_RUN_CONT":"UNKNOWN"));
00563     cp_compressor_state= (compressor_state==0)?
00564                              "COMPRESSOR_RUN_STOP":
00565                              ((compressor_state==1)?
00566                                   "COMPRESSOR_RUN_SINGLE":
00567                                   ((compressor_state==2)?"COMPRESSOR_RUN_CONT":"UNKNOWN"));
00568 
00569   save_p=lseek(fd_circ,0,SEEK_CUR); 
00570   rp=lseek(fd_circ,LSEEK_CIRC_TORP,SEEK_END); 
00571   wp=lseek(fd_circ,LSEEK_CIRC_TOWP,SEEK_END); 
00572   p=wp;
00573   while ((p>=0) & (nf<500)) {
00574    if (p==rp) nfl=nf;
00575    p=lseek(fd_circ,LSEEK_CIRC_PREV,SEEK_END);
00576    nf++;
00577   }
00578   buf_free=GLOBALPARS(G_FREECIRCBUF);
00579   buf_used=GLOBALPARS(G_CIRCBUFSIZE)-GLOBALPARS(G_FREECIRCBUF);
00580 
00581   lseek(fd_circ,save_p,SEEK_SET); 
00582   buf_free=lseek(fd_circ,LSEEK_CIRC_FREE,SEEK_END); 
00583   lseek(fd_circ,save_p,SEEK_SET); 
00584   buf_used=lseek(fd_circ,LSEEK_CIRC_USED,SEEK_END); 
00585   lseek(fd_circ,save_p,SEEK_SET); 
00586 
00587   sprintf (s,"<?xml version=\"1.0\"?>\n" \
00588              "<frame_pointers>\n" \
00589              "  <this>%d</this>\n" \
00590              "  <write>%d</write>\n" \
00591              "  <read>%d</read>\n" \
00592              "  <frames>%d</frames>\n" \
00593              "  <left>%d</left>\n" \
00594              "  <free>%d</free>\n" \
00595              "  <used>%d</used>\n" \
00596              "  <frame>%d</frame>\n" \
00597              "  <sensor_state>\"%s\"</sensor_state>\n" \
00598              "  <compressor_state>\"%s\"</compressor_state>\n" \
00599              "</frame_pointers>\n",
00600               save_p,
00601               wp,
00602               rp,
00603               nf-1,
00604               nfl,
00605               buf_free,
00606               buf_used,
00607               frame_number,
00608               cp_sensor_state,
00609               cp_compressor_state);
00610    printf("HTTP/1.0 200 OK\n");
00611    printf("Server: Elphel Imgsrv\n");
00612    printf("Content-Length: %d\n",strlen(s));
00613    printf("Content-Type: text/xml\n");
00614    printf("Pragma: no-cache\n");
00615    printf("\n");
00616    printf(s);
00618    close(fd_fparmsall); 
00619    D(fprintf (stderr,">%s< [%d bytes]\n",s,strlen(s)));
00620    return 0; 
00621 }
00622 //fwrite (&cbuffer[offset],1,bytesLeft,stdout);
00623 int out1x1gif(void) {
00624  char s[]="HTTP/1.0 200 OK\n" \
00625           "Server: Elphel Imgsrv\n" \
00626           "Content-Length: 35\n" \
00627           "Content-Type: image/gif\n" \
00628           "\n" \
00629           "GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00" \
00630           "\xff\xff\xff\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x4c" \
00631           "\x01\x00\x3b";
00632           fwrite (s,1,sizeof(s),stdout); 
00633    return 0; 
00634  }
00635 
00636 void errorMsgXML(char * msg) {
00637   char s[1024]; // was 701 acrtually
00638     sprintf (s,"<?xml version=\"1.0\"?>\n" \
00639              "<frame_params>\n" \
00640              "<error>%s</error>\n" \
00641              "</frame_params>\n",msg);
00642   D(fprintf (stderr,">%s< [%d bytes]",s,strlen(s)));
00643   printf("HTTP/1.0 200 OK\n");
00644   printf("Server: Elphel Imgsrv\n");
00645   printf("Content-Length: %d\n",strlen(s));
00646   printf("Content-Type: text/xml\n");
00647   printf("Pragma: no-cache\n");
00648   printf("\n");
00649   printf(s);
00650 }
00651 
00652 
00653 
00656 
00657 int  sendImage (int bufferImageData, int fd_circ, int use_Exif) {
00658    const char HeadFileName[]="/dev/jpeghead";
00659    const char ExifFileName[]="/dev/exif_exif";
00660    int  exifDataSize=0;
00662    int  frameParamPointer=0;
00663    struct interframe_params_t frame_params;
00665    int buff_size;
00666    int jpeg_len;   //bytes
00667    int jpeg_start; // bytes
00668    int fd_head;
00669    int fd_exif;
00670    int head_size;
00671    int jpeg_full_size, jpeg_this_size;
00672    char * jpeg_copy;
00673    int l,i;
00675    jpeg_start=lseek(fd_circ,0,SEEK_CUR); //get the current read pointer
00676    D(fprintf(stderr,"jpeg_start= (long)=0x%x\n",jpeg_start>>2));
00677    fd_head = open(HeadFileName, O_RDWR);
00678    if (fd_head<0) { // check control OK
00679      fprintf (stderr,"Error opening %s\n", HeadFileName);
00680      return -1;
00681    }
00682    lseek(fd_head,jpeg_start+1,SEEK_END); 
00683    head_size=lseek(fd_head,0,SEEK_END);
00684    if (head_size>JPEG_HEADER_MAXSIZE) {
00685      fprintf(stderr,"%s:%d: Too big JPEG header (%d > %d)",__FILE__,__LINE__,head_size, JPEG_HEADER_MAXSIZE );
00686      close (fd_head);
00687      return -2;
00688    }
00690     buff_size=lseek(fd_circ,0,SEEK_END);
00692     lseek(fd_circ, jpeg_start, SEEK_SET);
00693     D(fprintf(stderr,"position (longs)=0x%x\n", (int) lseek(fd_circ,0,SEEK_CUR)>>2));
00694 
00696 
00697    frameParamPointer=jpeg_start-32;
00698    if (frameParamPointer<0) frameParamPointer+=buff_size;
00699    memcpy (&frame_params, (unsigned long * ) &ccam_dma_buf[frameParamPointer>>2],32);
00700    jpeg_len=frame_params.frame_length;
00701    if (frame_params.signffff !=0xffff) {
00702      fprintf(stderr, "wrong signature - %d\r\n",(int) frame_params.signffff);
00703      close (fd_head);
00704      return -4;
00705    }
00706 
00707    if (use_Exif) {
00708      D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
00710      fd_exif = open(ExifFileName, O_RDONLY);
00711      if (fd_exif<0) { // check control OK
00712        fprintf (stderr,"Error opening %s\n", ExifFileName);
00713        close (fd_head);
00714        return -5;
00715      }
00716      exifDataSize=lseek(fd_exif,1,SEEK_END); // at the beginning of page 1 - position == page length
00717      if (exifDataSize < 0) exifDataSize=0; // error from lseek;
00718      if (!exifDataSize) close(fd_exif);
00719    } else {
00720       frame_params.meta_index=0;
00721       fd_exif=-1;
00722    }
00726 
00727    jpeg_full_size=jpeg_len+head_size+2+exifDataSize;
00728    if (bufferImageData) jpeg_this_size=jpeg_full_size;           
00729    else                 jpeg_this_size=head_size+exifDataSize;   
00730    jpeg_copy=malloc(jpeg_this_size);
00731    if (!jpeg_copy) {
00732       syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__,__LINE__,jpeg_this_size);
00734       for (i=0;i<10;i++) {
00735          usleep(((jpeg_this_size & 0x3ff) + 5) * 100); // up to 0.1 sec
00736          jpeg_copy=malloc(jpeg_this_size);
00737          if (jpeg_copy) break;
00738          syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__,__LINE__,jpeg_this_size);
00739       }
00740       if (!jpeg_copy) {
00741         syslog(LOG_ERR, "%s:%d malloc (%d) failed 10 times - giving up", __FILE__,__LINE__,jpeg_this_size);
00742         exit (1);
00743       }
00744     }
00745 
00746    lseek(fd_head,0,0);
00747    read (fd_head,&jpeg_copy[exifDataSize],head_size);
00748    close (fd_head);
00749    if (exifDataSize>0) {
00750        memcpy (jpeg_copy,&jpeg_copy[exifDataSize],2); 
00751        lseek(fd_exif,frame_params.meta_index,SEEK_END); 
00752        read (fd_exif,&jpeg_copy[2],exifDataSize);  
00753        close(fd_exif);
00754    }
00755    printf("Content-Type: image/jpeg\n");
00756    if (bufferImageData) { 
00757      l=head_size+exifDataSize;
00759      if ((jpeg_start+jpeg_len) > buff_size) { // two segments
00760        memcpy (&jpeg_copy[l], (unsigned long * ) &ccam_dma_buf[jpeg_start>>2],buff_size-jpeg_start);
00761        l+=buff_size-jpeg_start;
00762        memcpy (&jpeg_copy[l],(unsigned long * ) &ccam_dma_buf[0],jpeg_len-(buff_size-jpeg_start));
00763      } else {  
00764        memcpy (&jpeg_copy[l],(unsigned long * ) &ccam_dma_buf[jpeg_start>>2],jpeg_len);
00765      }
00766      memcpy (&jpeg_copy[jpeg_len+head_size+exifDataSize],trailer,2);
00767      printf("Content-Length: %d\n",jpeg_full_size);
00768      printf("\n");
00769      sendBuffer(jpeg_copy, jpeg_full_size);
00770    } else { 
00771      printf("Content-Length: %d\n",jpeg_full_size);
00772      printf("\n");
00773      sendBuffer(jpeg_copy, head_size+exifDataSize); //JPEG+Exif
00775      if ((jpeg_start+jpeg_len) > buff_size) { // two segments
00777         sendBuffer((void *) &ccam_dma_buf[jpeg_start>>2], buff_size-jpeg_start);
00779         sendBuffer((void *) &ccam_dma_buf[0], jpeg_len-(buff_size-jpeg_start));
00780      } else { // single segment
00782         sendBuffer((void *) &ccam_dma_buf[jpeg_start>>2], jpeg_len);
00783      }
00784      sendBuffer(trailer,2);
00785    }
00786    free(jpeg_copy);
00787    return 0;
00788 
00789 }
00790 
00791 
00793 void sendBuffer(void * buffer, int len) {
00794    int  bytesLeft=len;
00795    int  offset=0;
00796    int  bytesWritten;
00797    char * cbuffer= (char *) buffer;
00798 D(fprintf (stderr,"buffer=%p, len=%d\n",buffer, len));
00799    while (bytesLeft>0) {
00800 D(fprintf (stderr," --bytesLeft=%d\n",bytesLeft));
00801 
00802       bytesWritten= fwrite (&cbuffer[offset],1,bytesLeft,stdout);
00803       bytesLeft-=   bytesWritten;
00804       offset+=      bytesWritten;
00805    }
00806 }
00807 
00808 
00809 
00810 
00811 void listener_loop(int port)
00812 {
00813    char errormsg[1024];
00814    const char circbufFileName[]="/dev/circbuf";
00815    int fd_circ;
00816    int this_p; 
00817    int rslt;
00818    int buf_images=0;
00819    char buf [1024];
00820    int len=0;
00821    char * cp, *cp1, *cp2;
00822    int slow,skip; // reduce frame rate by slow
00823    int sent2socket=-1; // 1 - img, 2 - meta, 3 - pointers
00824    struct sockaddr_in sock;
00825    int res;
00826    int one=1;
00827    int buff_size;
00828    memset((char *)&sock, 0, sizeof(sock));
00829    sock.sin_port = htons(port);
00830    sock.sin_family = AF_INET;
00831    res = socket(AF_INET, SOCK_STREAM, 0);
00832    setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
00833    bind(res, (struct sockaddr * ) &sock,sizeof(sock));
00834    listen(res, 10);
00835    int exif_enable=1;
00836    while (1) {
00837      int fd;
00838      fd = accept(res,NULL,0);
00839      if (fd == -1) continue;
00840      signal(SIGCHLD, SIG_IGN); // no zombies, please!
00841 
00843      if (fork() == 0) {
00844        close(res);
00846        fflush(stdout);
00847        fflush(stderr);
00848        dup2(fd, 0);
00849        dup2(fd, 1);
00850        close(fd);
00852        if (fgets(buf, sizeof(buf)-1, stdin)) len=strlen(buf);
00853        cp=buf;
00854        strsep(&cp, "/?"); // ignore everything before first "/" or "?"
00855        if (cp) {
00858          cp1=strchr(cp,' ');
00859          if (cp1) cp1[0]='\0';
00860        } 
00861        if (!cp || (strlen(cp)==0)) { 
00862          printf("HTTP/1.0 200 OK\n");
00863          printf("Server: Elphel Imgsrv\n");
00864          printf("Content-Length: %d\n",strlen(url_args));
00865          printf("Content-Type: text/plain\n");
00866          printf("\n");
00867          printf(url_args);
00868          fflush(stdout);
00869         _exit(0);
00870        }
00872        fd_circ = open(circbufFileName, O_RDWR);
00873        if (fd_circ<0) { // check control OK
00874          fprintf (stderr,"Error opening %s\n", circbufFileName);
00875          out1x1gif();
00876          fflush(stdout);
00877         _exit(0);
00878        }
00880        buff_size=lseek(fd_circ,0,SEEK_END);
00882        ccam_dma_buf = (unsigned long *) mmap(0, buff_size, PROT_READ, MAP_SHARED, fd_circ, 0);
00883        if((int)ccam_dma_buf == -1) {
00884           fprintf(stderr, "Error in mmap\n");
00885           close(fd_circ); // - caller opened, caller - to close
00886           out1x1gif();
00887           fflush(stdout);
00888          _exit(0);
00889        }
00890        this_p=lseek(fd_circ,LSEEK_CIRC_LAST,SEEK_END);
00892        while ((cp1=strsep(&cp, "/?&"))) {
00894         if (strchr("0123456789",cp1[0])) {
00895           this_p= lseek(fd_circ,strtol(cp1, NULL, 10),SEEK_SET);
00896         } else if ((strcmp(cp1, "img")==0) || (strcmp(cp1, "bimg")==0)) {
00897           if (sent2socket>0) break; 
00898           if (lseek(fd_circ,LSEEK_CIRC_READY,SEEK_END)<0) 
00899             rslt=out1x1gif();
00900           else {
00901            printf("HTTP/1.0 200 OK\n");
00902            printf("Server: Elphel Imgsrv\n");
00903            printf("Expires: 0\n");
00904            printf("Pragma: no-cache\n");
00905            buf_images= (strcmp(cp1, "img")==0)?0:1;
00906            rslt=sendImage (buf_images, fd_circ, exif_enable); 
00907           }
00908           sent2socket=1;
00909           if (rslt<0) {
00910             if (sent2socket==1) out1x1gif();
00911             else {
00912                sprintf(errormsg,"sendImage error = %d (%s:line %d)",rslt,__FILE__,__LINE__);
00913                errorMsgXML(errormsg);
00914             }
00915           }
00916           fflush(stdout); 
00917 
00919         } else if ((strncmp(cp1, "mimg",4)==0) || (strncmp(cp1, "bmimg",5)==0) || (strncmp(cp1, "mbimg",5)==0)) {
00920           if (sent2socket>0) break; 
00921           if (lseek(fd_circ,LSEEK_CIRC_READY,SEEK_END)<0) 
00922             rslt=out1x1gif();
00923           else {
00924 //int  sendImage (int bufferImageData, int fd_circ, int use_Exif)
00925 //TODO:
00926            buf_images= (strncmp(cp1, "mimg",4)==0)?0:1;
00927            cp2=cp1+(buf_images?5:4);
00928            slow=strtol(cp2, NULL, 10);
00929            if (slow < 1) slow =1;
00930 
00931            printf("HTTP/1.0 200 OK\n");
00932            printf("Server: Elphel Imgsrv\n");
00933            printf("Expires: 0\n");
00934            printf("Pragma: no-cache\n");
00935            printf("Content-Type: multipart/x-mixed-replace;boundary=ElphelMultipartJPEGBoundary\n");
00936            rslt=0;
00937            while (rslt>=0) {
00938              printf("\n--ElphelMultipartJPEGBoundary\n");
00939              rslt=sendImage (buf_images, fd_circ, exif_enable); 
00940              fflush(stdout);
00941              if (rslt>=0) for (skip=0;skip<slow;skip++) {
00942                this_p=lseek(fd_circ,LSEEK_CIRC_NEXT, SEEK_END);
00944                if ((lseek(fd_circ,LSEEK_CIRC_VALID,SEEK_END) >= 0) && 
00945                    (lseek(fd_circ,LSEEK_CIRC_READY,SEEK_END) <  0) && 
00946                    (lseek(fd_circ,LSEEK_CIRC_VALID,SEEK_END) >= 0))   
00947                     this_p=lseek(fd_circ,LSEEK_CIRC_WAIT,SEEK_END);
00948                else this_p=lseek(fd_circ,LSEEK_CIRC_LAST, SEEK_END);
00949              }
00950            }
00951           _exit(0);
00952           }
00953         } else if (strcmp(cp1, "pointers")==0)   {
00954           if (sent2socket>0) break; 
00955           framePointersXML(fd_circ); 
00956           sent2socket=3;
00957           fflush(stdout); 
00958         } else if (strcmp(cp1, "meta")==0)   {
00959           if ((sent2socket>0) && (sent2socket!=2)) break; 
00960           metaXML(fd_circ,(sent2socket>0)?1:0); 
00961           sent2socket=2;
00962           fflush(stdout); 
00963         } else if (strcmp(cp1, "noexif")==0)   {
00964           exif_enable=0;
00965         } else if (strcmp(cp1, "exif")==0)   {
00966           exif_enable=1;
00967         } else if (strcmp(cp1, "torp")==0)   {
00968           this_p=lseek(fd_circ,LSEEK_CIRC_TORP, SEEK_END);
00969         } else if (strcmp(cp1, "towp")==0)   {
00970           this_p=lseek(fd_circ,LSEEK_CIRC_TOWP, SEEK_END);
00971         } else if (strcmp(cp1, "prev")==0)   {
00972           this_p=lseek(fd_circ,LSEEK_CIRC_PREV, SEEK_END);
00973         } else if (strcmp(cp1, "next")==0)   {
00974           this_p=lseek(fd_circ,LSEEK_CIRC_NEXT, SEEK_END);
00975         } else if (strcmp(cp1, "last")==0)   {
00976           this_p=lseek(fd_circ,LSEEK_CIRC_LAST, SEEK_END);
00977         } else if (strcmp(cp1, "first")==0)  {
00978           this_p=lseek(fd_circ,LSEEK_CIRC_FIRST,SEEK_END);
00979         } else if (strcmp(cp1, "second")==0) {
00980           this_p=lseek(fd_circ,LSEEK_CIRC_SCND, SEEK_END);
00981         } else if (strcmp(cp1, "save")==0)   {
00982           this_p=lseek(fd_circ,LSEEK_CIRC_SETP,SEEK_END);
00983         } else if (strcmp(cp1, "wait")==0)   {
00984                if ((lseek(fd_circ,LSEEK_CIRC_VALID,SEEK_END) >= 0) && 
00985                    (lseek(fd_circ,LSEEK_CIRC_READY,SEEK_END) <  0) && 
00986                    (lseek(fd_circ,LSEEK_CIRC_VALID,SEEK_END) >= 0))   
00987                   this_p=lseek(fd_circ,LSEEK_CIRC_WAIT,SEEK_END);
00988         } else if (strcmp(cp1, "favicon.ico")==0)   {
00990         } else {
00991           if (cp1[0]!='_') fprintf(stderr,"Unrecognized URL command: \"%s\" - ignoring\n",cp1); 
00992         }
00993      } 
00994      if (sent2socket<=0) { 
00995        out1x1gif();
00996      } else if (sent2socket==2) {
00997        metaXML(fd_circ,2); 
00998      }
00999 
01000      fflush(stdout); // probably it is not needed anymore, just in case
01001       _exit(0);
01002     } // end of child process
01003     close(fd); // parent
01004   } // while (1)
01005 }
01006 
01008 int main(int argc, char *argv[])
01009 {
01010      const char usage[]=   "Usage:\n%s -p <port_number>\n" \
01011                            "Start image server, bind it to port <port_number>\n";
01012 
01013      int port;
01014      if ((argc < 3) || (strcasecmp(argv[1], "-p"))) {
01015      printf (usage,argv[0]);
01016      printf (url_args);
01017      return 0;
01018    }
01019    port=strtol(argv[2], NULL, 10);
01020    if (!port) {printf ("Invalid port number %d\n", port); return -1;}
01021    signal(SIGCHLD, SIG_IGN); // no zombies, please!
01022    if (fork() == 0) { // child
01023      listener_loop(port);
01024       _exit(0); // should not get here?
01025     } // end of child process
01026    return 0;
01027 }

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