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 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.14  2008/04/22 22:14:56  elphel
00022 *!  Added malloc failures handling, syslog logging of such events
00023 *!
00024 *!  Revision 1.13  2008/04/16 20:30:33  elphel
00025 *!  added optional fps reduction to multipart JPEGs
00026 *!
00027 *!  Revision 1.11  2008/04/07 09:13:35  elphel
00028 *!  Changes related to new Exif generation/processing
00029 *!
00030 *!  Revision 1.10  2008/03/22 04:39:53  elphel
00031 *!  remove complaints about "&_time=..."
00032 *!
00033 *!  Revision 1.9  2007/12/03 08:28:45  elphel
00034 *!  Multiple changes, mostly cleanup
00035 *!
00036 *!  Revision 1.8  2007/11/16 08:56:19  elphel
00037 *!  Added support for 2 additional commands to check circbuf usage
00038 *!
00039 *!  Revision 1.7  2007/11/04 23:25:16  elphel
00040 *!  removed extra (used during debug) munmap that caused segfault after sending "img" (so no /nxt/save)
00041 *!
00042 *!  Revision 1.6  2007/11/04 05:47:40  elphel
00043 *!  Cleaned up from debug code inserted to fight mmap/caching bug (fixed by now)
00044 *!
00045 *!  Revision 1.5  2007/11/01 18:59:37  elphel
00046 *!  debugging mmap/caching problems
00047 *!
00048 *!  Revision 1.4  2007/10/30 16:56:06  elphel
00049 *!  release 7.1.4.5 - working on "can not find 0xffff in frame parameters" bug. Temporary fix
00050 *!
00051 *!  Revision 1.3  2007/10/27 00:55:32  elphel
00052 *!  untested revision - need to go
00053 *!
00054 *!  Revision 1.2  2007/10/11 06:42:28  elphel
00055 *!  Fixed bug - /meta command should return trivial xml file, not 1x1 pixel gif
00056 *!
00057 *!  Revision 1.1.1.1  2007/10/02 19:44:54  elphel
00058 *!  This is a fresh tree based on elphel353-2.10
00059 *!
00060 *!  Revision 1.4  2007/10/02 19:44:54  elphel
00061 *!  More functionality (buffer manipulation commands, clean interface, xml responces)
00062 *!
00063 *!  Revision 1.3  2007/09/29 16:21:25  elphel
00064 *!  removed IOCTL usage from /dev/circbuf, improved comments, other minor changes
00065 *!
00066 *!  Revision 1.2  2007/09/25 23:35:16  elphel
00067 *!  added Exif initialization, made it to work in background mode
00068 *!
00069 *!  Revision 1.1  2007/09/23 06:49:10  elphel
00070 *!  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)
00071 *!
00072 *!
00073 */ 
00074 #include <unistd.h>
00075 #include <stdio.h>
00076 #include <stdlib.h>
00077 #include <signal.h>
00078 #include <fcntl.h>
00079 #include <errno.h>
00080 #include <sys/types.h>
00081 #include <sys/socket.h>
00082 #include <sys/stat.h>
00083 //#include <ctype.h>
00084 //#include <getopt.h>
00085 #include <time.h>
00086 #include <string.h>
00087 #include <syslog.h>
00088 
00089 #include <netinet/in.h>
00090 #include <sys/mman.h>           /* mmap */
00091 #include <sys/ioctl.h>
00092 
00093 #include <asm/elphel/c313a.h>
00094 #include <asm/elphel/exifa.h>
00095 #include <asm/elphel/ext353.h>
00096 #include <asm/byteorder.h>
00097 
00098 #define D(x)
00099 //#define D(x) fprintf(stderr,"%s:%d:",__FILE__,__LINE__);x
00100 
00101 //#define USEHTTP10(x)
00102 #define USEHTTP10(x) x
00103 
00104 // HEADER_SIZE is defined to be larger than actual header (later - with EXIF)  to use compile-time buffer
00105 #define JPEG_HEADER_SIZE    0x26f // will not change
00106 
00107 #define TRAILER_SIZE   0x02
00108 #define MAP_OPTIONS MAP_FILE|MAP_PRIVATE
00109 
00110 unsigned long * ccam_dma_buf;           /* mmapped array */
00111 
00112 char trailer[TRAILER_SIZE] = {0xff,0xd9};
00113 
00114 const char url_args[]="This server supports sequence of commands entered in the URL (separated by \"/\", case sensitive )\n" \
00115                       "executing them from left to right as they appear in the URL\n" \
00116                       "img -      send image at the current pointer (if it is first command - use last acquired image, if none availabe - send 1x1 gif)\n" \
00117                       "bimg -     same as above, but save the whole image in the memory before sending - useful to avoid overruns with slow connection \n" \
00118                       "mimg[n] -  send images as a multipart JPEG (all commands after will be ignored), possible to specify optional fps reduction\n" \
00119                       "           i.e. mimg4 - skip 3 frames for each frame output (1/4 fps) \n" \
00120                       "bmimg[n] - same as above, buffered\n" \
00121                       "pointers - send XML-formatted data about frames available in the camera circular buffer)\n\n" \
00122                       "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" \
00123                       "are present in the URL 1x1 pixel gif will be returned to the client after executing the URL command.\n\n" \
00124                       "torp -   set frame pointer to global read pointer, maintained by the camera driver. If frame at that pointer\n" \
00125                       "         is invalid, use scnd (see below)\n" \
00126                       "towp -   set frame pointer to hardware write pointer - position where next frame will be aquired\n" \
00127                       "prev -   move to previous frame in buffer, nop if there are none\n" \
00128                       "next -   move to the next frame in buffer (will stop at write pointer, see towp above)\n" \
00129                       "last -   move to the most recently acquired frame, or to write pointer if there are none.\n" \
00130                       "         this command is implied at the start of the url command sequence.\n" \
00131                       "first -  move to the oldest frame still available in the buffer. It is not safe to rely on it if\n" \
00132                       "         more frames are expected - data might be overwritten at any moment and the output will be corrupted.\n" \
00133                       "second - move to the second oldest frame in the buffer - somewhat safer than \"first\" - there will be time for\n" \
00134                       "         \"next\" command at least before frame data (and pointer structures) will be overwritten.\n" \
00135                       "save   - save current frame pointer as a global read pointer that holds it values between server requests.\n" \
00136                       "         This pointer is shared between all the clients and applications that use it.\n" \
00137                       "wait   - Wait until there will be a frame at current pointer ready\n";
00138 int  sendImage (int bufferImageData, int fd_circ, int use_Exif);
00139 void sendBuffer(void * buffer, int len);
00140 void listener_loop(int port);
00141 void errorMsgXML(char * msg);
00142 int  framePointersXML(int fd_circ);
00143 int  out1x1gif(void);
00144 
00145 int framePointersXML(int fd_circ) {
00146   const char SensParsFileName[]="/dev/sensorpars";
00147   unsigned long * imageParamsR;
00148   int fd_sens, senspars_size;
00149   char s[256]; // 136;
00150   char * compressor_state;
00151   int p, wp, rp;
00152   int nf=0;
00153   int nfl=0;
00154   int buf_free, buf_used;
00155   int save_p; 
00156 
00157 
00158 
00159    fd_sens = open(SensParsFileName, O_RDWR);
00160    if (fd_sens<0) { // check control OK
00161       D(fprintf (stderr,"Error opening %s\n", SensParsFileName));
00162       return -2;
00163    }
00165    senspars_size=lseek(fd_sens,0,SEEK_END);
00166    imageParamsR = (unsigned long *) mmap(0, senspars_size, PROT_READ, MAP_SHARED, fd_sens, 0);
00167    if((int)imageParamsR == -1) {
00168      D(fprintf (stderr,"Error in mmap of %s\n",SensParsFileName));
00169      close(fd_sens);
00170      return -3;
00171    }
00172 
00173 
00174   save_p=lseek(fd_circ,0,SEEK_CUR); 
00175   rp=lseek(fd_circ,CIRCLSEEK_TORP,SEEK_END); 
00176   wp=lseek(fd_circ,CIRCLSEEK_TOWP,SEEK_END); 
00177   p=wp;
00178   while ((p>=0) & (nf<500)) {
00179    if (p==rp) nfl=nf;
00180    p=lseek(fd_circ,CIRCLSEEK_PREV,SEEK_END);
00181    nf++;
00182   }
00183   buf_free=imageParamsR[P_FREECIRCBUF];
00184   buf_used=imageParamsR[P_CIRCBUFSIZE]-imageParamsR[P_FREECIRCBUF];
00185   compressor_state=(imageParamsR[P_CAMSEQSTATE]==CAMSEQ_RUN)?"running":
00186                      ((imageParamsR[P_CAMSEQSTATE]==CAMSEQ_SINGLE)?"acquiring":
00187                       ((imageParamsR[P_CAMSEQSTATE]==CAMSEQ_STOP)?"stoppping":
00188                        ((imageParamsR[P_CAMSEQSTATE]==CAMSEQ_JPEG)?"stopped":
00189                         ((imageParamsR[P_CAMSEQSTATE]==CAMSEQ_OFF)?"reset":"other"))));
00190 
00191 
00192   lseek(fd_circ,save_p,SEEK_SET); 
00193   buf_free=lseek(fd_circ,CIRCLSEEK_FREE,SEEK_END); 
00194   lseek(fd_circ,save_p,SEEK_SET); 
00195   buf_used=lseek(fd_circ,CIRCLSEEK_USED,SEEK_END); 
00196   lseek(fd_circ,save_p,SEEK_SET); 
00197 
00198   sprintf (s,"<?xml version=\"1.0\"?>\n" \
00199              "<frame_pointers>\n" \
00200              "  <this>%d</this>\n" \
00201              "  <write>%d</write>\n" \
00202              "  <read>%d</read>\n" \
00203              "  <frames>%d</frames>\n" \
00204              "  <left>%d</left>\n" \
00205              "  <free>%d</free>\n" \
00206              "  <used>%d</used>\n" \
00207              "  <compressor_state>\"%s\"</compressor_state>\n" \
00208              "</frame_pointers>\n",
00209               save_p,
00210               wp,
00211               rp,
00212               nf-1,
00213               nfl,
00214               buf_free,
00215               buf_used,
00216               compressor_state);
00217    D(fprintf (stderr,">%s< [%d bytes]",s,strlen(s)));
00218    printf("HTTP/1.0 200 OK\n");
00219    printf("Server: Elphel Imgsrv\n");
00220    printf("Content-Length: %d\n",strlen(s));
00221    printf("Content-Type: text/xml\n");
00222    printf("Pragma: no-cache\n");
00223    printf("\n");
00224    printf(s);
00226    close(fd_sens); 
00227    return 0; 
00228 }
00229 //fwrite (&cbuffer[offset],1,bytesLeft,stdout);
00230 int out1x1gif(void) {
00231  char s[]="HTTP/1.0 200 OK\n" \
00232           "Server: Elphel Imgsrv\n" \
00233           "Content-Length: 35\n" \
00234           "Content-Type: image/gif\n" \
00235           "\n" \
00236           "GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00" \
00237           "\xff\xff\xff\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x4c" \
00238           "\x01\x00\x3b";
00239           fwrite (s,1,sizeof(s),stdout); 
00240    return 0; 
00241  }
00242 
00243 void errorMsgXML(char * msg) {
00244   char s[1024]; // was 701 acrtually
00245     sprintf (s,"<?xml version=\"1.0\"?>\n" \
00246              "<frame_params>\n" \
00247              "<error>%s</error>\n" \
00248              "</frame_params>\n",msg);
00249   D(fprintf (stderr,">%s< [%d bytes]",s,strlen(s)));
00250   printf("HTTP/1.0 200 OK\n");
00251   printf("Server: Elphel Imgsrv\n");
00252   printf("Content-Length: %d\n",strlen(s));
00253   printf("Content-Type: text/xml\n");
00254   printf("Pragma: no-cache\n");
00255   printf("\n");
00256   printf(s);
00257 }
00258 
00259 
00260 
00263 
00264 int  sendImage (int bufferImageData, int fd_circ, int use_Exif) {
00265    const char HeadFileName[]="/dev/jpeghead";
00266    const char ExifFileName[]="/dev/exif_exif";
00267 //   char jpegHeader [JPEG_HEADER_SIZE];
00268    int  exifDataSize=0;
00270    int  frameParamPointer=0;
00271    struct frame_params_t frame_params;
00273    int buff_size;
00274 //   unsigned long * ccam_dma_buf;           /* mmapped array */
00275 //   volatile unsigned long * ccam_dma_buf;           /* mmapped array */
00276    int jpeg_len;   //bytes
00277    int jpeg_start; // bytes
00278    int fd_head;
00279    int fd_exif;
00280    int head_size;
00281    int jpeg_full_size, jpeg_this_size;
00282    char * jpeg_copy;
00283    int l,i;
00285    jpeg_start=lseek(fd_circ,0,SEEK_CUR); //get the current read pointer
00286    D(fprintf(stderr,"jpeg_start= (long)=0x%x\n",jpeg_start>>2));
00287    fd_head = open(HeadFileName, O_RDWR);
00288    if (fd_head<0) { // check control OK
00289      fprintf (stderr,"Error opening %s\n", HeadFileName);
00290      return -1;
00291    }
00292    head_size=lseek(fd_head,0,SEEK_END);
00293    if (head_size>JPEG_HEADER_SIZE) {
00294      fprintf(stderr,"%s:%d: Too big JPEG header (%d > %d)",__FILE__,__LINE__,head_size, JPEG_HEADER_SIZE );
00295      close (fd_head);
00296      return -2;
00297    }
00299     buff_size=lseek(fd_circ,0,SEEK_END);
00301     lseek(fd_circ, jpeg_start, SEEK_SET);
00302     D(fprintf(stderr,"position (longs)=0x%x\n", (int) lseek(fd_circ,0,SEEK_CUR)>>2));
00303 //#define MAP_OPTIONS MAP_FILE|MAP_PRIVATE
00304 
00306 /*
00307    ccam_dma_buf = (unsigned long *) mmap(0, buff_size, PROT_READ, MAP_SHARED, fd_circ, 0);
00308    if((int)ccam_dma_buf == -1) {
00309      fprintf(stderr, "Error in mmap\n");
00310      close (fd_head);
00311 //     close(fd_circ); - caller opened, caller - to close
00312      return -3;
00313    }
00314 */
00315 //   char exifData [MAX_EXIF_SIZE];
00316 //   int  exifDataSize=0;
00318    frameParamPointer=jpeg_start-32;
00319 //   if (exifIndexPointer<0) exifIndexPointer+=buff_size;
00320    if (frameParamPointer<0) frameParamPointer+=buff_size;
00321 //   memcpy (&frame_exif, (unsigned long * ) &ccam_dma_buf[exifIndexPointer>>2],8);
00322    memcpy (&frame_params, (unsigned long * ) &ccam_dma_buf[frameParamPointer>>2],32);
00323 //   jpeg_len=frame_exif.frame_length;
00324    jpeg_len=frame_params.frame_length;
00325 //   if (frame_exif.signffff !=0xffff) {
00326    if (frame_params.signffff !=0xffff) {
00327 //     fprintf(stderr, "wrong signature - %d\r\n",(int) frame_exif.signffff);
00328      fprintf(stderr, "wrong signature - %d\r\n",(int) frame_params.signffff);
00329      close (fd_head);
00330      return -4;
00331    }
00332 
00333    if (use_Exif) {
00334 //     D(fprintf(stderr,"frame_exif.meta_index=0x%x\n",(int) frame_exif.meta_index));
00335      D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
00337      fd_exif = open(ExifFileName, O_RDONLY);
00338      if (fd_exif<0) { // check control OK
00339        fprintf (stderr,"Error opening %s\n", ExifFileName);
00340        close (fd_head);
00341        return -5;
00342      }
00343      exifDataSize=lseek(fd_exif,1,SEEK_END); // at the beginning of page 1 - position == page length
00344      if (exifDataSize < 0) exifDataSize=0; // error from lseek;
00345      if (!exifDataSize) close(fd_exif);
00346    } else {
00347 //      frame_exif.meta_index=0;
00348       frame_params.meta_index=0;
00349       fd_exif=-1;
00350    }
00353    if (exifDataSize>0 ) {
00357      lseek(fd_head,jpeg_start+1,SEEK_END); 
00358    }
00359 
00361 
00362    jpeg_full_size=jpeg_len+head_size+2+exifDataSize;
00363 //   if (bufferImageData) jpeg_copy=malloc(jpeg_full_size);           /// header+frame
00364 //   else                 jpeg_copy=malloc(head_size+exifDataSize);   /// only header
00365    if (bufferImageData) jpeg_this_size=jpeg_full_size;           
00366    else                 jpeg_this_size=head_size+exifDataSize;   
00367    jpeg_copy=malloc(jpeg_this_size);
00368    if (!jpeg_copy) {
00369       syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__,__LINE__,jpeg_this_size);
00371       for (i=0;i<10;i++) {
00372          usleep(((jpeg_this_size & 0x3ff) + 5) * 100); // up to 0.1 sec
00373          jpeg_copy=malloc(jpeg_this_size);
00374          if (jpeg_copy) break;
00375          syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__,__LINE__,jpeg_this_size);
00376       }
00377       if (!jpeg_copy) {
00378         syslog(LOG_ERR, "%s:%d malloc (%d) failed 10 times - giving up", __FILE__,__LINE__,jpeg_this_size);
00379         exit (1);
00380       }
00381     }
00382 
00383    lseek(fd_head,0,0);
00384    read (fd_head,&jpeg_copy[exifDataSize],head_size);
00385    close (fd_head);
00386    if (exifDataSize>0) {
00387        memcpy (jpeg_copy,&jpeg_copy[exifDataSize],2); 
00388 //       lseek(fd_exif,frame_exif.meta_index,SEEK_END); //! select meta page to use (matching frame)
00389        lseek(fd_exif,frame_params.meta_index,SEEK_END); 
00390        read (fd_exif,&jpeg_copy[2],exifDataSize);  
00391        close(fd_exif);
00392    }
00393    printf("Content-Type: image/jpeg\n");
00394    if (bufferImageData) { 
00395      l=head_size+exifDataSize;
00397      if ((jpeg_start+jpeg_len) > buff_size) { // two segments
00398        memcpy (&jpeg_copy[l], (unsigned long * ) &ccam_dma_buf[jpeg_start>>2],buff_size-jpeg_start);
00399        l+=buff_size-jpeg_start;
00400        memcpy (&jpeg_copy[l],(unsigned long * ) &ccam_dma_buf[0],jpeg_len-(buff_size-jpeg_start));
00401      } else {  
00402        memcpy (&jpeg_copy[l],(unsigned long * ) &ccam_dma_buf[jpeg_start>>2],jpeg_len);
00403      }
00404      memcpy (&jpeg_copy[jpeg_len+head_size+exifDataSize],trailer,2);
00405      printf("Content-Length: %d\n",jpeg_full_size);
00406      printf("\n");
00407      sendBuffer(jpeg_copy, jpeg_full_size);
00408    } else { 
00409      printf("Content-Length: %d\n",jpeg_full_size);
00410      printf("\n");
00411      sendBuffer(jpeg_copy, head_size+exifDataSize); //JPEG+Exif
00413      if ((jpeg_start+jpeg_len) > buff_size) { // two segments
00415         sendBuffer((void *) &ccam_dma_buf[jpeg_start>>2], buff_size-jpeg_start);
00417         sendBuffer((void *) &ccam_dma_buf[0], jpeg_len-(buff_size-jpeg_start));
00418      } else { // single segment
00420         sendBuffer((void *) &ccam_dma_buf[jpeg_start>>2], jpeg_len);
00421      }
00422      sendBuffer(trailer,2);
00423    }
00424    free(jpeg_copy);
00425    return 0;
00426 
00427 }
00428 
00429 
00431 void sendBuffer(void * buffer, int len) {
00432    int  bytesLeft=len;
00433    int  offset=0;
00434    int  bytesWritten;
00435    char * cbuffer= (char *) buffer;
00436 D(fprintf (stderr,"buffer=%p, len=%d\n",buffer, len));
00437    while (bytesLeft>0) {
00438 D(fprintf (stderr," --bytesLeft=%d\n",bytesLeft));
00439 
00440       bytesWritten= fwrite (&cbuffer[offset],1,bytesLeft,stdout);
00441       bytesLeft-=   bytesWritten;
00442       offset+=      bytesWritten;
00443    }
00444 }
00445 
00446 
00447 
00448 
00449 void listener_loop(int port)
00450 {
00451    char errormsg[1024];
00452    const char circbufFileName[]="/dev/circbuf";
00453    int fd_circ;
00454    int this_p; 
00455    int rslt;
00456    int buf_images=0;
00457    char buf [1024];
00458    int len=0;
00459    char * cp, *cp1, *cp2;
00460    int slow,skip; // reduce frame rate by slow
00461    int sent2socket=-1; // 1 - img, 2 - meta, 3 - pointers
00462    struct sockaddr_in sock;
00463    int res;
00464    int one=1;
00465    int buff_size;
00466    memset((char *)&sock, 0, sizeof(sock));
00467    sock.sin_port = htons(port);
00468    sock.sin_family = AF_INET;
00469    res = socket(AF_INET, SOCK_STREAM, 0);
00470    setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
00471    bind(res, (struct sockaddr * ) &sock,sizeof(sock));
00472    listen(res, 10);
00473    int exif_enable=1;
00474    while (1) {
00475      int fd;
00476      fd = accept(res,NULL,0);
00477      if (fd == -1) continue;
00478      signal(SIGCHLD, SIG_IGN); // no zombies, please!
00479 
00481      if (fork() == 0) {
00482        close(res);
00484        fflush(stdout);
00485        fflush(stderr);
00486        dup2(fd, 0);
00487        dup2(fd, 1);
00488        close(fd);
00490        if (fgets(buf, sizeof(buf)-1, stdin)) len=strlen(buf);
00491        cp=buf;
00492        strsep(&cp, "/?"); // ignore everything before first "/" or "?"
00493        if (cp) {
00496          cp1=strchr(cp,' ');
00497          if (cp1) cp1[0]='\0';
00498        } 
00499        if (!cp || (strlen(cp)==0)) { 
00500          printf("HTTP/1.0 200 OK\n");
00501          printf("Server: Elphel Imgsrv\n");
00502          printf("Content-Length: %d\n",strlen(url_args));
00503          printf("Content-Type: text/plain\n");
00504          printf("\n");
00505          printf(url_args);
00506          fflush(stdout);
00507         _exit(0);
00508        }
00510        fd_circ = open(circbufFileName, O_RDWR);
00511        if (fd_circ<0) { // check control OK
00512          fprintf (stderr,"Error opening %s\n", circbufFileName);
00513          out1x1gif();
00514          fflush(stdout);
00515         _exit(0);
00516        }
00518        buff_size=lseek(fd_circ,0,SEEK_END);
00520        ccam_dma_buf = (unsigned long *) mmap(0, buff_size, PROT_READ, MAP_SHARED, fd_circ, 0);
00521        if((int)ccam_dma_buf == -1) {
00522           fprintf(stderr, "Error in mmap\n");
00523           close(fd_circ); // - caller opened, caller - to close
00524           out1x1gif();
00525           fflush(stdout);
00526          _exit(0);
00527        }
00528        this_p=lseek(fd_circ,CIRCLSEEK_LAST,SEEK_END);
00530        while ((cp1=strsep(&cp, "/?&"))) {
00532         if (strchr("0123456789",cp1[0])) {
00533           this_p= lseek(fd_circ,strtol(cp1, NULL, 10),SEEK_SET);
00534         } else if ((strcmp(cp1, "img")==0) || (strcmp(cp1, "bimg")==0)) {
00535           if (sent2socket>0) break; 
00536           if (lseek(fd_circ,CIRCLSEEK_READY,SEEK_END)<0) 
00537             rslt=out1x1gif();
00538           else {
00539            printf("HTTP/1.0 200 OK\n");
00540            printf("Server: Elphel Imgsrv\n");
00541            printf("Expires: 0\n");
00542            printf("Pragma: no-cache\n");
00543            buf_images= (strcmp(cp1, "img")==0)?0:1;
00544            rslt=sendImage (buf_images, fd_circ, exif_enable); 
00545           }
00546           sent2socket=1;
00547           if (rslt<0) {
00548             if (sent2socket==1) out1x1gif();
00549             else {
00550                sprintf(errormsg,"sendImage error = %d (%s:line %d)",rslt,__FILE__,__LINE__);
00551                errorMsgXML(errormsg);
00552             }
00553           }
00554           fflush(stdout); 
00555 
00557         } else if ((strncmp(cp1, "mimg",4)==0) || (strncmp(cp1, "bmimg",5)==0) || (strncmp(cp1, "mbimg",5)==0)) {
00558           if (sent2socket>0) break; 
00559           if (lseek(fd_circ,CIRCLSEEK_READY,SEEK_END)<0) 
00560             rslt=out1x1gif();
00561           else {
00562 //int  sendImage (int bufferImageData, int fd_circ, int use_Exif)
00563 //TODO:
00564            buf_images= (strncmp(cp1, "mimg",4)==0)?0:1;
00565            cp2=cp1+(buf_images?5:4);
00566            slow=strtol(cp2, NULL, 10);
00567            if (slow < 1) slow =1;
00568 
00569            printf("HTTP/1.0 200 OK\n");
00570            printf("Server: Elphel Imgsrv\n");
00571            printf("Expires: 0\n");
00572            printf("Pragma: no-cache\n");
00573            printf("Content-Type: multipart/x-mixed-replace;boundary=ElphelMultipartJPEGBoundary\n");
00574            rslt=0;
00575            while (rslt>=0) {
00576              printf("\n--ElphelMultipartJPEGBoundary\n");
00577              rslt=sendImage (buf_images, fd_circ, exif_enable); 
00578              fflush(stdout);
00579              if (rslt>=0) for (skip=0;skip<slow;skip++) {
00580                this_p=lseek(fd_circ,CIRCLSEEK_NEXT, SEEK_END);
00582                if ((lseek(fd_circ,CIRCLSEEK_VALID,SEEK_END) >= 0) && 
00583                    (lseek(fd_circ,CIRCLSEEK_READY,SEEK_END) <  0) && 
00584                    (lseek(fd_circ,CIRCLSEEK_VALID,SEEK_END) >= 0))   
00585                     this_p=lseek(fd_circ,CIRCLSEEK_WAIT,SEEK_END);
00586                else this_p=lseek(fd_circ,CIRCLSEEK_LAST, SEEK_END);
00587              }
00588            }
00589           _exit(0);
00590           }
00591         } else if (strcmp(cp1, "pointers")==0)   {
00592           if (sent2socket>0) break; 
00593           framePointersXML(fd_circ); 
00594           sent2socket=3;
00595           fflush(stdout); 
00596         } else if (strcmp(cp1, "noexif")==0)   {
00597           exif_enable=0;
00598         } else if (strcmp(cp1, "exif")==0)   {
00599           exif_enable=1;
00600         } else if (strcmp(cp1, "torp")==0)   {
00601           this_p=lseek(fd_circ,CIRCLSEEK_TORP, SEEK_END);
00602         } else if (strcmp(cp1, "towp")==0)   {
00603           this_p=lseek(fd_circ,CIRCLSEEK_TOWP, SEEK_END);
00604         } else if (strcmp(cp1, "prev")==0)   {
00605           this_p=lseek(fd_circ,CIRCLSEEK_PREV, SEEK_END);
00606         } else if (strcmp(cp1, "next")==0)   {
00607           this_p=lseek(fd_circ,CIRCLSEEK_NEXT, SEEK_END);
00608         } else if (strcmp(cp1, "last")==0)   {
00609           this_p=lseek(fd_circ,CIRCLSEEK_LAST, SEEK_END);
00610         } else if (strcmp(cp1, "first")==0)  {
00611           this_p=lseek(fd_circ,CIRCLSEEK_FIRST,SEEK_END);
00612         } else if (strcmp(cp1, "second")==0) {
00613           this_p=lseek(fd_circ,CIRCLSEEK_SCND, SEEK_END);
00614         } else if (strcmp(cp1, "save")==0)   {
00615           this_p=lseek(fd_circ,CIRCLSEEK_SETP,SEEK_END);
00616         } else if (strcmp(cp1, "wait")==0)   {
00617                if ((lseek(fd_circ,CIRCLSEEK_VALID,SEEK_END) >= 0) && 
00618                    (lseek(fd_circ,CIRCLSEEK_READY,SEEK_END) <  0) && 
00619                    (lseek(fd_circ,CIRCLSEEK_VALID,SEEK_END) >= 0))   
00620                   this_p=lseek(fd_circ,CIRCLSEEK_WAIT,SEEK_END);
00621 /*
00622           if (((dbg_test1=(lseek(fd_circ,CIRCLSEEK_VALID,SEEK_END))) >= 0) && //! no sense to wait if the pointer is invalid
00623               (((dbg_test2=lseek(fd_circ,CIRCLSEEK_READY,SEEK_END))) <0))     //! or the frame is already ready
00624                  this_p=lseek(fd_circ,CIRCLSEEK_WAIT,SEEK_END);
00625                  dbg_test3=this_p;
00626 */
00627         } else {
00628           if (cp1[0]!='_') fprintf(stderr,"Unrecognized URL command: \"%s\" - ignoring\n",cp1); 
00629         }
00630      } 
00631      if (sent2socket<=0) { 
00632        out1x1gif();
00633        fflush(stdout);
00634      }
00635 
00636      fflush(stdout); // probably it is not needed anymore, just in case
00637       _exit(0);
00638     } // end of child process
00639     close(fd); // parent
00640   } // while (1)
00641 }
00642 
00644 int main(int argc, char *argv[])
00645 {
00646      const char usage[]=   "Usage:\n%s -p <port_number>\n" \
00647                            "Start image server, bind it to port <port_number>\n";
00648 
00649      int port;
00650      if ((argc < 3) || (strcasecmp(argv[1], "-p"))) {
00651      printf (usage,argv[0]);
00652      printf (url_args);
00653      return 0;
00654    }
00655    port=strtol(argv[2], NULL, 10);
00656    if (!port) {printf ("Invalid port number %d\n", port); return -1;}
00657    signal(SIGCHLD, SIG_IGN); // no zombies, please!
00658    if (fork() == 0) { // child
00659      listener_loop(port);
00660       _exit(0); // should not get here?
00661     } // end of child process
00662    return 0;
00663 }

Generated on Thu Aug 7 16:18:59 2008 for elphel by  doxygen 1.5.1