/**************************************************************/ /* */ /* This is an example program for direct server access */ /* to OptiView. It is written in a simplistic fashion */ /* so that it will be easy to modify and port. */ /* It will compile in Solaris using the following command: */ /* */ /* gcc direct.c -lsocket -o direct */ /* */ /* The program basically emulates a browser doing */ /* a file upload form. */ /* */ /**************************************************************/ #include #include #include #include #include #include #include #include main(int argc, char **argv) { int debug=0; int sd; int ret; char *pnt; int size_received = 0; struct sockaddr_in addr; struct stat input_stat; char boundary[128]= "---------------------------7cd1e7391000ea"; char http_header[4096]; char content_header[4096]; char content_trailer[4096]; int before_size; int bytes_sent; int after_size = 0; int after_width = 0; int after_height = 0; int after_quality = 0; char after_option[16] = ""; char after_type[16] = ""; char *before_buffer; char *after_buffer; char *filename_in; int input_fd; char *filename_out; int output_fd; if (argc < 3) { fprintf(stderr,"Usage: %s input_filename output_filename [-d]\n",argv[0]); fflush(stderr); return(1); } filename_in = argv[1]; filename_out = argv[2]; if (argc == 4) { if (!strcmp(argv[3],"-d")) debug=1; } /******************************************************/ /* */ /* This part is the multi-part form data headers */ /* that is normally send when using a file upload */ /* form. */ /* */ /******************************************************/ *content_header=0; strcat(content_header,boundary); strcat(content_header,"\n"); strcat(content_header,"Content-Disposition: form-data; name=\"imagefile\"; filename=\""); strcat(content_header,argv[1]); strcat(content_header,"\"\n"); strcat(content_header,"Content-Type: image/gif\n"); /* this is not passed by all browsers */ strcat(content_header,"\n"); /******************************************************/ /* */ /* Check for an input file with something in it */ /* to send and then read it into a memory buffer. */ /* */ /* The important part here is that before_buffer */ /* holds the contents of the GIF to be processed */ /* and before_size is the length of the data in */ /* in that buffer. */ /* */ /******************************************************/ ret = stat(filename_in,&input_stat); if (ret == -1) { fprintf(stderr,"Error: file %s does not exist.\n",filename_in); fflush(stderr); return(1); } before_size = input_stat.st_size; if (before_size <= 0) { fprintf(stderr,"Error: file %s zero size.\n",filename_in); fflush(stderr); return(1); } before_buffer = malloc(before_size); input_fd = open(filename_in, O_RDONLY, 0 ); if (debug) { fprintf(stderr,"input_fd=%d errno=%d\n",input_fd,errno); fflush(stderr); } ret = read(input_fd,before_buffer,before_size); if (debug) { fprintf(stderr,"read ret=%d errno=%d\n",ret,errno); fflush(stderr); } close(input_fd); /******************************************************/ /* */ /* This continuation of the multi-part form-data */ /* has all of the other input fields. */ /* */ /* Boundary and newline placement is critical! */ /* */ /******************************************************/ *content_trailer=0; /******************************************************/ /* */ /* Your account number */ /* Make sure your server's IP address is registered */ /* */ /******************************************************/ strcat(content_trailer,boundary); strcat(content_trailer,"\n"); strcat(content_trailer,"Content-Disposition: form-data; name=\"account\"\n"); strcat(content_trailer,"\n"); strcat(content_trailer,"654321\n"); /******************************************************/ /* */ /* Values for height and width parameters */ /* */ /* */ /* Change: */ /* 25 = change to 25 pixels */ /* a25 = add 25 pixels */ /* s25 = subtract 25 pixels */ /* 25p = change 25 percent of original */ /* a25p = add 25 percent */ /* s25p = subtract 25 percent */ /* */ /* change on either height or width will do */ /* a purportional resize */ /* */ /* change on either both and width will do */ /* a distorted resize */ /* */ /* */ /* Minimum and Maximum: */ /* min250 = minimum of 250 pixels */ /* max250 = maximum of 250 pixels */ /* */ /* */ /* order is important, first amount to change, */ /* then min size and then max size */ /* any of three parts can be omitted */ /* a25pmin100max250 */ /* */ /* (add 25%, minimum size 100, maximum 250) */ /* */ /******************************************************/ /******************************************************/ /* */ /* Values for comp parameter */ /* */ /* */ /* original = resize only */ /* clean = Graphic is cleaned up only */ /* light = some compression */ /* medium = recommended compression (default) */ /* heavy = some changes on some images */ /* maximum = really crunched (use with care) */ /* extreme = even more! (use with care) */ /* */ /******************************************************/ /******************************************************/ /* */ /* Values for style parameter */ /* */ /* */ /* GIF = Option A GIF adaptive */ /* JPG = Option D/F Standard and high-res JPG */ /* PJPG = Option E/G Progressive and high-res JPG */ /* */ /******************************************************/ /* strcat(content_trailer,boundary); strcat(content_trailer,"\n"); strcat(content_trailer,"Content-Disposition: form-data; name=\"height\"\n"); strcat(content_trailer,"\n"); strcat(content_trailer,"100p\n"); */ /* strcat(content_trailer,boundary); strcat(content_trailer,"\n"); strcat(content_trailer,"Content-Disposition: form-data; name=\"width\"\n"); strcat(content_trailer,"\n"); strcat(content_trailer,"100p\n"); */ /* strcat(content_trailer,boundary); strcat(content_trailer,"\n"); strcat(content_trailer,"Content-Disposition: form-data; name=\"style\"\n"); strcat(content_trailer,"\n"); strcat(content_trailer,"JPG\n"); */ /* strcat(content_trailer,boundary); strcat(content_trailer,"\n"); strcat(content_trailer,"Content-Disposition: form-data; name=\"style\"\n"); strcat(content_trailer,"\n"); strcat(content_trailer,"GIF\n"); */ /* strcat(content_trailer,boundary); strcat(content_trailer,"\n"); strcat(content_trailer,"Content-Disposition: form-data; name=\"size\"\n"); strcat(content_trailer,"\n"); strcat(content_trailer,"50000\n"); */ /* strcat(content_trailer,boundary); strcat(content_trailer,"\n"); strcat(content_trailer,"Content-Disposition: form-data; name=\"comp\"\n"); strcat(content_trailer,"\n"); strcat(content_trailer,"medium\n"); */ strcat(content_trailer,boundary); strcat(content_trailer,"--"); strcat(content_trailer,"\n"); /******************************************************/ /* */ /* Standard http POST request */ /* */ /* Referer and User-Agent are probably not critical */ /* but they help and if it works why break it. */ /* */ /******************************************************/ *http_header=0; strcat(http_header,"POST /PMV HTTP/1.0\n"); strcat(http_header,"Referer: http://www.mysite.com/\n"); strcat(http_header,"User-Agent: Image Robot\n"); strcat(http_header,"Content-type: multipart/form-data; boundary="); strcat(http_header,boundary); strcat(http_header,"\n"); sprintf(&http_header[strlen(http_header)],"Content-Length: %d\n",strlen(content_header)+before_size+strlen(content_trailer)); strcat(http_header,"Cache-Control: No-Cache\n"); strcat(http_header,"\n"); /******************************************************/ /* */ /* Server choices (in order of best performance) */ /* */ /* www.optiview.com 65.19.141.154 SFO */ /* uswest.optiview.com 65.19.141.154 SFO */ /* proxysin.optiview.com 203.124.102.106 singapore*/ /* */ /* It would be best to do an ip address lookup */ /* It is possible IP/Addresses might change */ /* */ /* we use port 80 because it gets through filewalls */ /* and all of the logging and multiple request */ /* handling is already rock solid. */ /* (plus you can test it from a web page form!) */ /* */ /******************************************************/ memset(&addr,0,sizeof(addr)); addr.sin_family=AF_INET; { char addr_c[4]; addr_c[0] = 65; addr_c[1] = 19; addr_c[2] = 141; addr_c[3] = 154; memcpy(&addr.sin_addr,addr_c,4); } /* addr.sin_addr.S_un.S_un_b.s_b1=65; addr.sin_addr.S_un.S_un_b.s_b2=19; addr.sin_addr.S_un.S_un_b.s_b3=141; addr.sin_addr.S_un.S_un_b.s_b4=154; */ addr.sin_port=htons(80); /* open a plain old socket internet style */ sd = socket(PF_INET,SOCK_STREAM,IPPROTO_IP); if (debug) { fprintf(stderr,"sd=%d errno=%d\n",sd,errno); fflush(stderr); } if (sd < 0) { fprintf(stderr,"Error: errno %d on open socket\n",errno); fflush(stderr); free(before_buffer); return(1); } /* connect to the server using the socket */ ret = connect(sd,(struct sockaddr *)&addr,sizeof(addr)); if (debug) fprintf(stderr,"connect_ret=%d errno=%d\n",ret,errno); if (ret < 0) { fprintf(stderr,"errno %d on connect to server\n",errno); fflush(stderr); free(before_buffer); close(sd); return(1); } /* send HTTP headers */ ret=send(sd,http_header,strlen(http_header),0); if (debug) { fprintf(stderr,"send ret=%d,errno=%d\n",ret,errno); fflush(stderr); } if (ret < 0) { fprintf(stderr,"Error: errno %d on send A\n",errno); fflush(stderr); free(before_buffer); close(sd); return(1); } /* send multipart headers */ ret=send(sd,content_header,strlen(content_header),0); if (debug) { fprintf(stderr,"send ret=%d,errno=%d\n",ret,errno); fflush(stderr); } if (ret < 0) { fprintf(stderr,"Error: errno %d on send B\n",errno); fflush(stderr); free(before_buffer); close(sd); return(1); } /* send the file sending a huge chunk of data (16K plus?) in one */ /* call can overrun the buffers in some operating systems so we */ /* send bite size chunks */ for (bytes_sent = 0; bytes_sent < before_size; bytes_sent += 8192) { int bytes = before_size - bytes_sent; if (bytes > 8192) bytes = 8192; ret=send(sd,&before_buffer[bytes_sent],bytes,0); if (debug) { fprintf(stderr,"send ret=%d,errno=%d\n",ret,errno); fflush(stderr); } if (ret < 0) { fprintf(stderr,"Error: errno %d on send C\n",errno); fflush(stderr); free(before_buffer); close(sd); return(1); } } /* send the other input fields */ ret=send(sd,content_trailer,strlen(content_trailer)+1,0); if (debug) { fprintf(stderr,"send ret=%d,errno=%d\n",ret,errno); fflush(stderr); } if (ret < 0) { fprintf(stderr,"Error: errno %d on send D\n",errno); fflush(stderr); free(before_buffer); close(sd); return(1); } /******************************************************/ /* */ /* This version of recv blocks until data is received */ /* or the socket is closed by the far end. */ /* */ /* For sizes over 1M this should be modified. */ /* */ /******************************************************/ #define MAX_BUFFER 1000000 after_buffer = malloc(MAX_BUFFER); memset(after_buffer,0,MAX_BUFFER); while (ret=recv(sd,&after_buffer[size_received],MAX_BUFFER-size_received,0)) { if (debug) { fprintf(stderr,"recv_ret=%d,errno=%d\n",ret,errno); fflush(stderr); } size_received += ret; } if (debug) { fprintf(stderr,"mesg_size=%d,message = <%s>,errno=%d\n",size_received,after_buffer,errno); fflush(stderr); } if (!size_received) { /* The server program probably aborted. */ /* If repeatable call in a bug report! */ fprintf(stderr,"Error: Received Size %d\n",size_received - (pnt - after_buffer)); fflush(stderr); free(before_buffer); free(after_buffer); close(sd); return(1); } /******************************************************/ /* */ /* Check to make sure you got the whole image. */ /* */ /* Content-Length should match the recevied size */ /* after the two newlines. */ /* */ /******************************************************/ if (debug) { fprintf(stderr,"Checking the received image:\n"); fflush(stderr); } pnt = strstr(after_buffer,"Image-Error:"); if (pnt) { pnt += 11; /* If there is problem with the data, the "contents" will */ /* Come back with error GIF and Image-Error: will be set */ /* a numaric and text description */ /* You'll get this if you send garbage or an html file etc.*/ fprintf(stderr,"Error: Server returned: %s\n",pnt); fflush(stderr); free(before_buffer); free(after_buffer); close(sd); return(1); } pnt = strstr(after_buffer,"Image-Height:"); if (pnt) { pnt += 14; after_height = atoi(pnt); } pnt = strstr(after_buffer,"Image-Width:"); if (pnt) { pnt += 13; after_width = atoi(pnt); } pnt = strstr(after_buffer,"Image-Type:"); if (pnt) { pnt += 12; strncpy(after_type,pnt,3); after_type[3]=0; } pnt = strstr(after_buffer,"Image-Option:"); if (pnt) { pnt += 14; strncpy(after_option,pnt,5); after_option[5]=0; if (pnt = strchr(after_option,' ')) *pnt = 0; } pnt = strstr(after_buffer,"Image-Quality:"); if (pnt) { pnt += 15; after_quality = atoi(pnt); } pnt = strstr(after_buffer,"Content-Length:"); if (pnt) { pnt += 16; after_size = atoi(pnt); pnt = strstr(pnt,"\r\n\r\n"); } if (pnt) { pnt += 4; if (after_size <= size_received - (pnt - after_buffer)) { /* Hey! It worked! Here we write it to a file, but you could */ /* store it in a memory buffer etc.... */ /* The image starts at pnt for length after_size */ output_fd = open(filename_out, O_WRONLY | O_TRUNC | O_CREAT, 0644 ); ret = write(output_fd,pnt,after_size); close(output_fd); } else { /* If there is problem with the network it might show up here */ /* an incomplete transfer. Try again. */ fprintf(stderr,"Error: Received Size %d is less than Content-Length %d\n",size_received - (pnt - after_buffer),after_size); fflush(stderr); free(before_buffer); free(after_buffer); close(sd); return(1); } } else { /* The server program probably may have a bug. */ /* If repeatable call in a bug report! */ fprintf(stderr,"Error: No Content-Length Returned\n"); fflush(stderr); free(before_buffer); free(after_buffer); close(sd); return(1); } if (debug) { fprintf(stderr,"Size = %d, Width = %d, Height = %d, Type = %s Option = %s Quality = %d\n",after_size,after_width,after_height,after_type,after_option,after_quality); fflush(stderr); } free(before_buffer); free(after_buffer); close(sd); return(0); }