4577547 [rkeene@sledge /home/rkeene/devel/libopennet-0.9.9]$ cat -n opennet.c
  1 #include "compat.h"
  2 
  3 #ifdef HAVE_SYS_SOCKET_H
  4 #include <sys/socket.h>
  5 #endif
  6 #ifdef HAVE_SYS_TYPES_H
  7 #include <sys/types.h>
  8 #endif
  9 #ifdef HAVE_SYS_STAT_H
 10 #include <sys/stat.h>
 11 #endif
 12 #ifdef HAVE_STRING_H
 13 #include <string.h>
 14 #endif
 15 #ifdef HAVE_STDLIB_H
 16 #include <stdlib.h>
 17 #endif
 18 #ifdef HAVE_UNISTD_H
 19 #include <unistd.h>
 20 #endif
 21 #ifdef HAVE_FCNTL_H
 22 #include <fcntl.h>
 23 #endif
 24 #ifdef HAVE_STDIO_H
 25 #include <stdio.h>
 26 #endif
 27 #ifdef HAVE_GETPEERNAME
 28 #ifdef HAVE_SYS_SOCKET_H
 29 #include <sys/socket.h>
 30 #endif
 31 #ifdef HAVE_NETINET_IN_H
 32 #include <netinet/in.h>
 33 #endif
 34 #endif
 35 
 36 #include "net.h"
 37 #include "opennet.h"
 38 
 39 #ifndef MSG_WAITALL
 40 #define MSG_WAITALL 0
 41 #endif
 42 
 43 /*
 44  * Legacy stub, please ignore.
 45  */
 46 int opennet_init(void) {
 47     return(0);
 48 }
 49 
 50 /*
 51     Replace 
 52         @@OSNM@@    OS Name (linux, freebsd, sunos, etc)
 53         @@OSVR@@    OS version (2.2.x, 4.2, 5.8, etc)
 54         @@OSVS@@    OS version (short) (2.2, 4.2, 5.8, etc)
 55         @@ARCH@@    Arch (i386, sparc64, sun4u, sun4m, etc)
 56 */
 57 char *parse_url_subst(const char *src) {
 58     char *retval = NULL;
 59 
 60     if (!strstr(src, "@@")) {
 61         return(strdup(src));
 62     }
 63 
 64     return(retval);
 65 }
 66 
 67 /*
 68  * Parse a URL into its components
 69  */
 70 static int parse_url(char *url, char **scheme, char **user, char **pass, char **host, int *port, char **path) {
 71     char *tmptr, *schemeptr, *pathptr, *userptr, *passptr, *hostptr, *portptr;
 72 
 73     if (!url) {
 74         return(-1);
 75     }
 76 
 77     tmptr = strstr(url, "://");
 78     if (!tmptr) {
 79         return(-1);
 80     }
 81 
 82     if (strlen(tmptr) <= 3) {
 83         return(-1);
 84     }
 85 
 86     *tmptr = '\0';
 87     schemeptr = url;
 88 
 89     tmptr += 3;
 90 
 91     pathptr = strchr(tmptr, '/');
 92 
 93     if (pathptr) {
 94         *pathptr = '\0';
 95         pathptr++;
 96     } else {
 97         pathptr = "";
 98     }
 99 
100     hostptr = strchr(tmptr, '@');
101     if (hostptr) {
102         *hostptr = '\0';
103         hostptr++;
104         userptr = tmptr;
105         passptr = strchr(userptr, ':');
106         if (passptr) {
107             *passptr = '\0';
108             passptr++;
109         }
110     } else {
111         userptr = NULL;
112         passptr = NULL;
113         hostptr = tmptr;
114     }
115 
116     portptr = strchr(hostptr, ':');
117     if (portptr) {
118         *portptr = '\0';
119         portptr++;
120         *port = strtoul(portptr, NULL, 10);
121     } else {
122         if (strcasecmp(schemeptr, "http") == 0) {
123             *port = 80;
124         } else if (strcasecmp(schemeptr, "ftp") == 0) {
125             *port = 21;
126         } else {
127             *port = 0;
128         }
129     }
130 
131     *scheme = schemeptr;
132     *user = userptr;
133     *pass = passptr;
134     *host = hostptr;
135     *path = pathptr;
136 
137     return(0);
138 }
139 
140 static ssize_t read_net_internal(int fd, void *buf, size_t count, int socketStatus) {
141     ssize_t retval = 0;
142     ssize_t read_ret;
143     int socket = 0;
144 #ifdef HAVE_GETPEERNAME
145     int gpn_ret;
146     struct sockaddr_in tmp;
147     int tmplen;
148 
149     if (socketStatus < 0) {
150         tmplen = sizeof(tmp);
151 
152         gpn_ret = getpeername(fd, (struct sockaddr *) &tmp, &tmplen);
153 
154         if (gpn_ret >= 0) {
155             socket = 1;
156         } else {
157             socket = 0;
158         }
159     } else {
160         socket = socketStatus;
161     }
162 #else
163     socket = socketStatus;
164 #endif
165 
166     while (count) {
167         if (socket) {
168             read_ret = recv(fd, buf, count, 0);
169         } else {
170             read_ret = read(fd, buf, count);
171         }
172 
173         if (read_ret == 0) {
174             break;
175         }
176 
177         if (read_ret < 0) {
178             retval = read_ret;
179             break;
180         }
181 
182         count -= read_ret;
183         buf += read_ret;
184         retval += read_ret;
185     }
186 
187     return(retval);
188 }
189 
190 static int open_net_http(char *user, char *pass, char *host, int port, char *path, int flags, off_t offset, off_t
	*length) {
191     unsigned long long content_length = 0;
192     ssize_t read_ret, sink_bytes = 0;
193     ssize_t send_ret, recv_ret;
194     char httpcmd[4096], charbuf, httpreply[1024], *http_response;
195     char garbage[4096];
196     int bytes_to_read;
197     int fd;
198     int snprintf_ret;
199     int http_response_code = 0;
200     int newlinecount = 0, linenum = 0, i = 0;
201 
202     fd = net_connect_tcp(host, port);
203 
204     if (fd < 0) {
205         return(-1);
206     }
207 
208     if (offset == 0) {
209         snprintf_ret = snprintf(httpcmd, sizeof(httpcmd), "GET /%s HTTP/1.0\015\012Host: %s\015\012\015\012", path,
	host);
210     } else {
211         snprintf_ret = snprintf(httpcmd, sizeof(httpcmd), "GET /%s HTTP/1.0\015\012Host: %s\015\012Range:
	bytes=%llu-\015\012\015\012", path, host, (unsigned long long) offset);
212     }
213 
214     if (snprintf_ret >= sizeof(httpcmd)) {
215         return(-1);
216     }
217 
218     send_ret = send(fd, httpcmd, snprintf_ret, 0);
219     if (send_ret != snprintf_ret) {
220         net_close(fd);
221         return(-1);
222     }
223 
224     while (1) {
225         recv_ret = recv(fd, &charbuf, 1, MSG_WAITALL);
226 
227         if (charbuf == '\015' || charbuf == '\012') {
228             if (i > 0) {
229                 httpreply[i] = '\0';
230                 if (linenum == 0) {
231 
232                     if (strlen(httpreply) < 9) {
233                         net_close(fd);
234                         return(-1);
235                     }
236 
237                     http_response = httpreply + 9;
238                     http_response_code = strtoul(http_response, NULL, 10);
239                     switch (http_response_code) {
240                         case 206:
241                             if (offset == 0) {
242                                 CHECKPOINT;
243                                 net_close(fd);
244                                 return(-1);
245                             }
246                             break;
247                         case 200:
248                             if (offset != 0) {
249                                 sink_bytes = offset;
250                             }
251                             break;
252                         case 301:
253                         case 302:
254                             break;
255                         case 404:
256                             CHECKPOINT;
257                         default:
258                             net_close(fd);
259                             return(-1);
260                     }
261                 } else {
262                     if (strncasecmp(httpreply, "Content-Length:", 15) == 0) {
263                         content_length = strtoull(httpreply + 16, NULL, 10);
264                         if (offset != 0 && http_response_code == 206) {
265                             content_length += (unsigned long long) offset;
266                         }
267                         if (length) {
268                             *length = content_length;
269                         }
270                     }
271                     if (http_response_code == 301 || http_response_code == 302) {
272                         if (strncasecmp(httpreply, "Location:", 9) == 0) {
273                             net_close(fd);
274                             return(open_net(httpreply + 10, flags, 0));
275                         }
276                     }
277                 }
278             }
279             newlinecount++;
280             linenum++;
281             i = 0;
282         } else {
283             newlinecount = 0;
284             httpreply[i++] = charbuf;
285         }
286 
287         if (newlinecount == 4) {
288             break;
289         }
290 
291         if (recv_ret <= 0) {
292             net_close(fd);
293             return(-1);
294         }
295     }
296 
297     if (sink_bytes) {
298         while (sink_bytes) {
299             bytes_to_read = sink_bytes;
300             if (bytes_to_read > sizeof(garbage)) {
301                 bytes_to_read = sizeof(garbage);
302             }
303 
304             read_ret = read_net_internal(fd, garbage, bytes_to_read, 1);
305             if (read_ret <= 0) {
306                 SPOTVAR_I(read_ret);
307                 net_close(fd);
308                 return(-1);
309             }
310 
311             sink_bytes -= read_ret;
312         }
313     }
314 
315     return(fd);
316 }
317 
318 static int open_net_ftp(char *user, char *pass, char *host, int port, char *path, int flags, off_t offset, off_t
	*length) {
319     return(-1);
320 }
321 
322 static int open_net_internal(const char *pathname, int flags, mode_t mode, int *socket, off_t offset, off_t *length) {
323     char *pathname_dup;
324     char *scheme, *user, *pass, *host, *path;
325     off_t lseek_ret;
326     int port = 0;
327     int parse_ret;
328     int retval = -1;
329 
330     if (socket) {
331         *socket = 0;
332     }
333 
334     if (!pathname) {
335         retval = open(pathname, flags, mode);
336         if (offset && retval >= 0) {
337             lseek_ret = lseek(retval, offset, SEEK_SET);
338             if (lseek_ret != offset) {
339                 close(retval);
340                 return(-1);
341             }
342         }
343         return(retval);
344     }
345 
346     pathname_dup = strdup(pathname);
347 
348     if (!pathname_dup) {
349         retval = open(pathname, flags, mode);
350         if (offset && retval >= 0) {
351             lseek_ret = lseek(retval, offset, SEEK_SET);
352             if (lseek_ret != offset) {
353                 close(retval);
354                 return(-1);
355             }
356         }
357         return(retval);
358     }
359 
360     parse_ret = parse_url(pathname_dup, &scheme, &user, &pass, &host, &port, &path);
361 
362     if (parse_ret < 0 || port == 0 || !host || !scheme) {
363         free(pathname_dup);
364         retval = open(pathname, flags, mode);
365         if (offset && retval >= 0) {
366             lseek_ret = lseek(retval, offset, SEEK_SET);
367             if (lseek_ret != offset) {
368                 close(retval);
369                 return(-1);
370             }
371         }
372         return(retval);
373 
374     }
375 
376     if (length) {
377         *length = -1;
378     }
379 
380     if (strcasecmp(scheme, "http") == 0) {
381         retval = open_net_http(user, pass, host, port, path, flags, offset, length);
382     }
383 
384     if (strcasecmp(scheme, "ftp") == 0) {
385         retval = open_net_ftp(user, pass, host, port, path, flags, offset, length);
386     }
387 
388     free(pathname_dup);
389 
390     if (retval < 0) {
391         retval = open(pathname, flags, mode);
392         if (offset && retval >= 0) {
393             lseek_ret = lseek(retval, offset, SEEK_SET);
394             if (lseek_ret != offset) {
395                 close(retval);
396                 return(-1);
397             }
398         }
399     } else {
400         if (socket) {
401             *socket = 1;
402         }
403     }
404 
405     return(retval);
406 }
407 
408 NETFILE *fopen_net(const char *pathname, const char *mode) {
409     NETFILE *ret;
410     int is_sock;
411     off_t length;
412 
413     ret = malloc(sizeof(*ret));
414 
415     if (!ret) {
416         return(NULL);
417     }
418 
419     ret->fd = open_net_internal(pathname, O_RDONLY, 0666, &is_sock, 0, &length);
420 
421     if (ret->fd < 0) {
422         free(ret);
423         return(NULL);
424     }
425 
426     ret->free_buf = 1;
427     ret->bufsize_s = ret->bufsize = 32768;
428     ret->buf_s = ret->buf = malloc(ret->bufsize);
429     ret->bufused = 0;
430     ret->eof = 0;
431     ret->pos = 0;
432     ret->socket = is_sock;
433     ret->length = length;
434     ret->url = strdup(pathname);
435 
436     return(ret);
437 }
438 
439 int feof_net(NETFILE *stream) {
440     if (!stream) {
441         return(-1);
442     }
443 
444     return(stream->eof);
445 }
446 
447 size_t fread_net(void *ptr, size_t size, size_t nmemb, NETFILE *stream) {
448     ssize_t recv_ret;
449     size_t retval;
450     int bytes_to_copy;
451 
452     if (!stream) {
453         return(0);
454     }
455 
456     if (stream->fd >= 0) {
457         while (stream->bufused < (size * nmemb)) {
458             if (stream->socket) {
459                 recv_ret = recv(stream->fd, stream->buf + stream->bufused, stream->bufsize - stream->bufused,
	MSG_WAITALL);
460             } else {
461                 recv_ret = read(stream->fd, stream->buf + stream->bufused, stream->bufsize - stream->bufused);
462             }
463 
464             if (recv_ret <= 0) {
465                 net_close(stream->fd);
466                 stream->fd = -1;
467                 break;
468             }
469 
470             stream->bufused += recv_ret;
471 
472             if (stream->bufused >= (size * nmemb)) {
473                 break;
474             }
475 
476             /*
477              * If there is more data to be read, but the buffer is full
478              * try to make room, or quit trying to read data
479              */
480             if (stream->bufused == stream->bufsize) {
481                 if (stream->bufsize_s != stream->bufsize) {
482                     CHECKPOINT;
483                     memmove(stream->buf_s, stream->buf, stream->bufused);
484                     stream->buf = stream->buf_s;
485                     stream->bufsize = stream->bufsize_s;
486                 } else {
487                     break;
488                 }
489             }
490         }
491     }
492 
493     if (stream->bufused == 0) {
494         if (stream->fd < 0) {
495             stream->eof = 1;
496         }
497         return(0);
498     }
499 
500     bytes_to_copy = (size * nmemb);
501 
502     if (stream->bufused < bytes_to_copy) {
503         bytes_to_copy = stream->bufused;
504 
505         /* Adjust bytes_to_copy to be a multiple of size */
506         bytes_to_copy /= size;
507         bytes_to_copy *= size;
508     }
509 
510     memcpy(ptr, stream->buf, bytes_to_copy);
511     stream->buf += bytes_to_copy;
512     stream->bufused -= bytes_to_copy;
513     stream->bufsize -= bytes_to_copy;
514 
515     if (stream->bufused == 0) {
516         stream->buf = stream->buf_s;
517         stream->bufsize = stream->bufsize_s;
518     }
519 
520     retval = bytes_to_copy / size;
521     stream->pos += retval;
522 
523     return(retval);
524 }
525 
526 char *fgets_net(char *s, int size, NETFILE *stream) {
527     ssize_t recv_ret;
528     int bytes_to_copy;
529     char *stopptr;
530 
531     if (!stream) {
532         return(NULL);
533     }
534 
535     if (stream->fd >= 0) {
536         while (stream->bufused < size) {
537             if (stream->socket) {
538                 recv_ret = recv(stream->fd, stream->buf + stream->bufused, stream->bufsize - stream->bufused,
	MSG_WAITALL);
539             } else {
540                 recv_ret = read(stream->fd, stream->buf + stream->bufused, stream->bufsize - stream->bufused);
541             }
542 
543             if (recv_ret <= 0) {
544                 net_close(stream->fd);
545                 stream->fd = -1;
546                 break;
547             }
548 
549             stream->bufused += recv_ret;
550 
551             if (memchr(stream->buf, '\n', stream->bufused)) {
552                 break;
553             }
554         }
555     }
556 
557     if (stream->bufused == 0) {
558         if (stream->fd < 0) {
559             stream->eof = 1;
560         }
561         return(NULL);
562     }
563 
564     stopptr = memchr(stream->buf, '\n', stream->bufused);
565 
566     if (!stopptr) {
567         stopptr = stream->buf + stream->bufused;
568     } else {
569         stopptr++;
570     }
571 
572     bytes_to_copy = stopptr - stream->buf;
573 
574     if (size < bytes_to_copy) {
575         bytes_to_copy = size;
576     }
577 
578     memcpy(s, stream->buf, bytes_to_copy);
579 
580     if (bytes_to_copy < size) {
581         s[bytes_to_copy] = '\0';
582     } else {
583         s[size - 1] = '\0';
584     }
585 
586     stream->buf += bytes_to_copy;
587     stream->bufused -= bytes_to_copy;
588     stream->bufsize -= bytes_to_copy;
589     stream->pos += bytes_to_copy;
590 
591     if (stream->bufused == 0) {
592         stream->buf = stream->buf_s;
593         stream->bufsize = stream->bufsize_s;
594     }
595 
596     return(s);
597 }
598 
599 int fclose_net(NETFILE *stream) {
600     int fd;
601     int retval;
602     int is_sock;
603 
604     if (!stream) {
605         return(-1);
606     }
607 
608     fd = stream->fd;
609     is_sock = stream->socket;
610 
611     if (stream->buf_s && stream->free_buf) {
612         free(stream->buf_s);
613     }
614     if (stream->url) {
615         free(stream->url);
616     }
617 
618     free(stream);
619 
620     if (is_sock) {
621         retval = net_close(fd);
622     } else {
623         retval = close(fd);
624     }
625 
626     return(retval);
627 }
628 
629 int setvbuf_net(NETFILE *stream, char *buf, int mode, size_t size) {
630     if (!stream) {
631         return(-1);
632     }
633 
634     if (size < stream->bufused) {
635         return(-1);
636     }
637 
638     if (stream->buf_s && stream->free_buf) {
639         free(stream->buf_s);
640     }
641 
642     memcpy(buf, stream->buf, stream->bufused);
643 
644     stream->buf = buf;
645     stream->buf_s = buf;
646     stream->bufsize = size;
647     stream->bufsize_s = size;
648     stream->free_buf = 0;
649 
650     return(0);
651 }
652 
653 int open_net(const char *pathname, int flags, mode_t mode) {
654     int tmp;
655 
656     return(open_net_internal(pathname, flags, mode, &tmp, 0, NULL));
657 }
658 
659 ssize_t read_net(int fd, void *buf, size_t count) {
660     return(read_net_internal(fd, buf, count, -1));
661 }
662 
663 off_t lseek_net(int filedes, off_t offset, int whence) {
664     return(-1);
665 }
666 
667 int fseeko_net(NETFILE *stream, off_t offset, int whence) {
668     static char garbage[4096];
669     size_t fread_ret, bytes_to_read;
670     off_t newoffset, lseek_ret;
671     off_t newlength;
672     int newfd;
673 
674     if (!stream) {
675         return(-1);
676     }
677     if (stream->fd < 0) {
678         return(-1);
679     }
680 
681     switch (whence) {
682         case SEEK_CUR:
683             newoffset = stream->pos + offset;
684             break;
685         case SEEK_END:
686             newoffset = stream->length + offset;
687             break;
688         case SEEK_SET:
689             newoffset = offset;
690             break;
691         default:
692             CHECKPOINT;
693             return(-1);
694             break;
695     }
696 
697     if (newoffset < 0) {
698         return(-1);
699     }
700 
701     lseek_ret = lseek(stream->fd, newoffset, SEEK_SET);
702     if (lseek_ret != ((off_t) -1)) {
703         stream->pos = lseek_ret;
704         stream->buf = stream->buf_s;
705         stream->bufused = 0;
706         stream->bufsize = stream->bufsize_s;
707 
708         return(0);
709     }
710 
711     /*
712      * Read up to 4K of data to avoid opening a new connection
713      */
714     if (newoffset >= stream->pos && (newoffset - stream->pos < sizeof(garbage))) {
715         bytes_to_read = newoffset - stream->pos;
716         fread_ret = fread_net(garbage, sizeof(garbage[0]), bytes_to_read, stream);
717 
718         if (fread_ret == bytes_to_read) {
719             return(0);
720         }
721     }
722 
723     newfd = open_net_internal(stream->url, O_RDONLY, 0666, NULL, newoffset, &newlength);
724 
725     if (newfd < 0) {
726         return(-1);
727     }
728 
729     net_close(stream->fd);
730     stream->fd = newfd;
731     stream->pos = newoffset;
732     stream->buf = stream->buf_s;
733     stream->bufused = 0;
734     stream->bufsize = stream->bufsize_s;
735     stream->eof = 0;
736 
737     return(0);
738 }
739 
740 int fseek_net(NETFILE *stream, long offset, int whence) {
741     return(fseek_net(stream, offset, whence));
742 }
743 
744 off_t ftello_net(NETFILE *stream) {
745     if (!stream) {
746         return(-1);
747     }
748     if (stream->fd < 0) {
749         return(-1);
750     }
751 
752     return(stream->pos);
753 }
754 
755 long ftell_net(NETFILE *stream) {
756     return(ftello_net(stream));
757 }
758 
759 off_t flength_net(NETFILE *stream) {
760     if (!stream) {
761         return(-1);
762     }
763     if (stream->fd < 0) {
764         return(-1);
765     }
766 
767     return(stream->length);
768 }
4577548 [rkeene@sledge /home/rkeene/devel/libopennet-0.9.9]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2006-12-18 13:31:42