00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
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
00084
00085 #include <time.h>
00086 #include <string.h>
00087 #include <syslog.h>
00088
00089 #include <netinet/in.h>
00090 #include <sys/mman.h>
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
00100
00101
00102 #define USEHTTP10(x) x
00103
00104
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;
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];
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) {
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
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];
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
00268 int exifDataSize=0;
00270 int frameParamPointer=0;
00271 struct frame_params_t frame_params;
00273 int buff_size;
00274
00275
00276 int jpeg_len;
00277 int jpeg_start;
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);
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) {
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
00304
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00318 frameParamPointer=jpeg_start-32;
00319
00320 if (frameParamPointer<0) frameParamPointer+=buff_size;
00321
00322 memcpy (&frame_params, (unsigned long * ) &ccam_dma_buf[frameParamPointer>>2],32);
00323
00324 jpeg_len=frame_params.frame_length;
00325
00326 if (frame_params.signffff !=0xffff) {
00327
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
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) {
00339 fprintf (stderr,"Error opening %s\n", ExifFileName);
00340 close (fd_head);
00341 return -5;
00342 }
00343 exifDataSize=lseek(fd_exif,1,SEEK_END);
00344 if (exifDataSize < 0) exifDataSize=0;
00345 if (!exifDataSize) close(fd_exif);
00346 } else {
00347
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
00364
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);
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
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) {
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);
00413 if ((jpeg_start+jpeg_len) > buff_size) {
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 {
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;
00461 int sent2socket=-1;
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);
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, "/?");
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) {
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);
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
00563
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
00623
00624
00625
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);
00637 _exit(0);
00638 }
00639 close(fd);
00640 }
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);
00658 if (fork() == 0) {
00659 listener_loop(port);
00660 _exit(0);
00661 }
00662 return 0;
00663 }