Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals

io.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: io.c,v 1.31 2006/05/12 09:02:58 tat Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <unistd.h>
00013 #include <u/libu.h>
00014 #include <klone/io.h>
00015 #include <klone/io.h>
00016 #include <klone/ioprv.h>
00017 #include <klone/codec.h>
00018 
00019 enum { 
00020     IO_RD_BUFSZ = 4096, 
00021     IO_WR_BUFSZ = 4096
00022 };
00023 
00024 #define IO_WBUF_AVAIL(io) (io->wbsz - io->wcount)
00025 #define IO_WBUF_FULL(io) (io->wbsz == io->wcount)
00026 
00027 static inline int io_transform_codec_buffer(io_t *, codec_t *, char *, 
00028         size_t *);
00029 
00048 ssize_t io_pipe(io_t *out, io_t *in)
00049 {
00050     enum { BUFSZ = 4096 };
00051     char buf[BUFSZ];
00052     size_t count = 0;   /* # of bytes piped */
00053     ssize_t c;
00054 
00055     dbg_err_if (out == NULL);
00056     dbg_err_if (in == NULL);
00057     
00058     for(;;)
00059     {
00060         c = io_read(in, buf, BUFSZ);
00061         dbg_err_if(c < 0);
00062         if(c == 0)
00063             break; /* eof */
00064 
00065         /* write it out */
00066         dbg_err_if(io_write(out, buf, c) < 0);
00067 
00068         count += c;
00069     }
00070 
00071     return count;
00072 err:
00073     return -1;
00074 }
00075 
00092 int io_dup(io_t *io, io_t **pio)
00093 {
00094     dbg_return_if (io == NULL, ~0);
00095     dbg_return_if (pio == NULL, ~0);
00096     
00097     io->refcnt++;
00098 
00099     *pio = io;
00100 
00101     return 0;
00102 }
00103 
00117 ssize_t io_copy(io_t *out, io_t *in, size_t size)
00118 {
00119     enum { BUFSZ = 4096 };
00120     char buf[BUFSZ];
00121     size_t rem = size;
00122     ssize_t c;
00123 
00124     dbg_err_if (in == NULL);
00125     dbg_err_if (out == NULL);
00126 
00127     while(rem)
00128     {
00129         c = io_read(in, buf, MIN(BUFSZ, rem));
00130         dbg_err_if(c < 0);
00131         if(c == 0)
00132             break; /* eof */
00133 
00134         /* write it out */
00135         dbg_err_if(io_write(out, buf, c) < 0);
00136 
00137         rem -= c;
00138     }
00139 
00140     return size - rem;
00141 err:
00142     return -1;
00143 }
00144 
00145 
00159 ssize_t io_seek(io_t *io, size_t off)
00160 {
00161     dbg_err_if (io == NULL);
00162     dbg_err_if (io_flush(io));
00163 
00164     if(io->seek)
00165         return io->seek(io, off);
00166 err:
00167     return -1;
00168 }
00169 
00180 ssize_t io_tell(io_t *io)
00181 {
00182     dbg_err_if (io == NULL);
00183     dbg_err_if (io_flush(io));
00184 
00185     if(io->tell)
00186         return io->tell(io);
00187 err:
00188     return -1;
00189 }
00190 
00191 /* alloc the read buffer */
00192 static int io_rbuf_alloc(io_t *io)
00193 {
00194     dbg_err_if (io == NULL);
00195     
00196     io->rbsz = IO_RD_BUFSZ; /* set the buffer size */
00197 
00198     /* if a dup'd io_t already alloc'd a buffer then use it */
00199     io->rbuf = (char*)u_malloc(io->rbsz);
00200     dbg_err_if(io->rbuf == NULL);
00201     io->roff = 0;
00202 
00203     io->ubuf = (char*)u_malloc(io->rbsz);
00204     dbg_err_if(io->ubuf == NULL);
00205 
00206     return 0;
00207 err:
00208     return ~0;
00209 }
00210 
00211 /* alloc the write buffer */
00212 static int io_wbuf_alloc(io_t *io)
00213 {
00214     dbg_err_if (io == NULL);
00215 
00216     io->wbsz = IO_WR_BUFSZ; /* set the buffer size */
00217 
00218     /* if a dup'd io_t already alloc'd a buffer then use it */
00219     io->wbuf = (char*)u_malloc(io->wbsz);
00220     dbg_err_if(io->wbuf == NULL);
00221 
00222     return 0;
00223 err:
00224     return ~0;
00225 }
00226 
00227 static ssize_t io_transform(io_t *io, codec_t *codec, 
00228     char *dst, size_t *dcount, const char *src, size_t sz)
00229 {
00230     ssize_t c;
00231     size_t cavail, sdcount = *dcount; /* saved dcount */
00232 
00233     dbg_err_if (io == NULL);
00234     dbg_err_if (codec == NULL);
00235     dbg_err_if (src == NULL);
00236     dbg_err_if (dst == NULL);
00237     dbg_err_if (dcount == NULL);
00238 
00239     if(codec == TAILQ_LAST(&io->codec_chain, codec_chain_s))
00240     {
00241         /* last codec in the chain */
00242         c = codec->transform(codec, dst, dcount, src, sz); 
00243         dbg_err_if(c == 0 && *dcount == 0);
00244         return c;
00245     } else {
00246         c = 0;
00247         do
00248         {
00249             *dcount = sdcount;
00250             if(codec->ccount)
00251                 dbg_err_if(io_transform_codec_buffer(io, codec, dst, dcount));
00252             else
00253                 *dcount = 0; /* no bytes written to 'dst' */
00254 
00255             c = 0; /* zero byte of 'src' consumed */
00256             cavail = CODEC_BUFSZ - codec->ccount - codec->coff;
00257             if(sz && cavail)
00258             {
00259                 dbg_err_if((c = codec->transform(codec, 
00260                     codec->cbuf + codec->coff + codec->ccount, 
00261                     &cavail, src, sz)) < 0);
00262 
00263                 codec->ccount += cavail;
00264                 dbg_err_if(c == 0 && cavail == 0);
00265             }
00266         } while(c == 0 && *dcount == 0 && (codec->ccount || sz));
00267 
00268         return c;
00269     }
00270 
00271 err:
00272     return -1;
00273 }
00274 
00275 static inline int io_transform_codec_buffer(io_t *io, codec_t *codec, 
00276     char *dst, size_t *dcount)
00277 {
00278     ssize_t ct;
00279 
00280     dbg_err_if (io == NULL);
00281     dbg_err_if (codec == NULL);
00282     dbg_err_if (dst == NULL);
00283     dbg_err_if (dcount == NULL);
00284 
00285     if(codec->ccount)
00286     {
00287         dbg_err_if((ct = io_transform(io, TAILQ_NEXT(codec, np), 
00288             dst, dcount, codec->cbuf + codec->coff,codec->ccount)) < 0);
00289 
00290         codec->ccount -= ct;
00291 
00292         if(codec->ccount > 0)
00293             codec->coff += ct;
00294         else
00295             codec->coff = 0;
00296     }
00297 
00298     return 0;
00299 err:
00300     return ~0;
00301 }
00302 
00303 static inline ssize_t io_transfer(io_t *io, char *dst, size_t *dcount, 
00304         const char *src, size_t sz)
00305 {
00306     dbg_err_if (io == NULL);
00307     dbg_err_if (src == NULL);
00308     dbg_err_if (dst == NULL);
00309     dbg_err_if (dcount == NULL);
00310 
00311     if(!TAILQ_EMPTY(&io->codec_chain))
00312     {
00313         return io_transform(io, TAILQ_FIRST(&io->codec_chain), 
00314             dst, dcount, src, sz); 
00315     } else {
00316         ssize_t wr = MIN(sz, *dcount); 
00317         memcpy(dst, src, wr);
00318         *dcount = wr;
00319         return wr;
00320     }
00321 err:
00322     return -1;
00323 }
00324 
00325 static int io_chain_flush_chunk(io_t *io, char *dst, size_t *dcount)
00326 {
00327     int er;
00328     codec_t *codec;
00329     size_t sz, sdcount;
00330 
00331     dbg_err_if (io == NULL);
00332     dbg_err_if (dst == NULL);
00333     dbg_err_if (dcount == NULL);
00334 
00335     sdcount = *dcount;
00336 
00337     TAILQ_FOREACH(codec, &io->codec_chain, np)
00338     {
00339         *dcount = sdcount;
00340         if(codec == TAILQ_LAST(&io->codec_chain, codec_chain_s))
00341         {
00342             return codec->flush(codec, dst, dcount);
00343         } else {
00344             for(;;)
00345             {
00346                 *dcount = sdcount;
00347                 if(codec->ccount)
00348                 {
00349                     int rc = io_transform_codec_buffer(io, codec, dst, dcount);
00350                     dbg_err_if (rc);
00351 
00352                     if(*dcount)
00353                         return CODEC_FLUSH_CHUNK; /* call flush again */
00354                 } else
00355                     *dcount = 0; /* no bytes written to 'dst' */
00356 
00357                 sz = CODEC_BUFSZ - codec->ccount - codec->coff;
00358                 dbg_err_if((er = codec->flush(codec, 
00359                     codec->cbuf + codec->coff + codec->ccount, &sz)) < 0);
00360 
00361                 codec->ccount += sz;
00362 
00363                 if(er == CODEC_FLUSH_COMPLETE && codec->ccount == 0)
00364                     break; /* flush of this codec completed */
00365             } /* for */
00366         }
00367     }
00368 
00369     return CODEC_FLUSH_COMPLETE;
00370 err:
00371     return -1;
00372 }
00373 
00374 static int io_chain_flush(io_t *io)
00375 {
00376     enum { BUFSZ = 4096 };
00377     int er;
00378     size_t sz, count;
00379     char buf[BUFSZ], *ptr;
00380 
00381     dbg_err_if (io == NULL);
00382 
00383     for(;;)
00384     {
00385         /* note: we cannot write straight to the wbuf otherwise codec 
00386          * transform & flush functions cannot call io_write safely; so we use 
00387          * a temp buffer and memcpy it to the wbuf after flushing */
00388         count = BUFSZ;
00389         if((er = io_chain_flush_chunk(io, buf, &count)) == CODEC_FLUSH_COMPLETE)
00390             break; /* flush complete */
00391         
00392         dbg_err_if(er < 0);
00393 
00394         for(ptr = buf; count; )
00395         {
00396             if(IO_WBUF_FULL(io))
00397                 dbg_err_if(io_flush(io));
00398 
00399             sz = MIN(count, IO_WBUF_AVAIL(io));
00400             memcpy(io->wbuf + io->wcount, ptr, sz);
00401 
00402             count -= sz;
00403             io->wcount += sz;
00404             ptr += sz;
00405         }
00406     } 
00407 
00408     return 0;
00409 err:
00410     return ~0;
00411 }
00412 
00427 int io_free(io_t *io)
00428 {
00429     dbg_err_if (io == NULL);
00430     dbg_err_if (io->refcnt == 0);
00431 
00432     /* skip if this io_t has been dup'd and there are still one or more 
00433        references in use */
00434     if(--io->refcnt)
00435         return 0;
00436 
00437     /* flush, remove and free all codecs */
00438     dbg_if(io_codecs_remove(io));
00439 
00440     dbg_if(io_flush(io));
00441 
00442     /* free per dev resources */
00443     dbg_if(io->term(io));
00444 
00445     U_FREE(io->rbuf);
00446     U_FREE(io->ubuf);
00447     U_FREE(io->wbuf);
00448     U_FREE(io->name);
00449     U_FREE(io);
00450 
00451     return 0;
00452 err:
00453     return ~0;
00454 }
00455 
00456 /* refill the read buffer */
00457 static ssize_t io_underflow(io_t *io)
00458 {
00459     ssize_t c;
00460     size_t sz;
00461 
00462     dbg_err_if (io == NULL);
00463 
00464     if(io->rbuf == NULL)
00465         dbg_err_if(io_rbuf_alloc(io)); /* alloc the read buffer */
00466 
00467     while(io->rcount == 0)
00468     {
00469         if(io->ucount == 0)
00470         {   /* fetch some bytes from the device and fill the rbuffer */
00471             dbg_err_if((c = io->read(io, io->ubuf, io->rbsz)) < 0);
00472             if(c == 0)
00473             {   /* eof, try to get some buffered (already transformed) bytes 
00474                    from the codec */
00475                 if(!TAILQ_EMPTY(&io->codec_chain))
00476                 {
00477                     sz = io->rbsz;
00478                     c = io_chain_flush_chunk(io, io->rbuf, &sz);
00479                     dbg_err_if(c < 0);
00480                     io->rcount += sz;
00481                     io->roff = 0;
00482                     if(c == 0)
00483                         io->eof++;
00484                 }
00485                 break;
00486             }
00487             io->ucount += c;
00488         }
00489 
00490         /* transform all data in the buffer */
00491         sz = io->rbsz - io->rcount;
00492         dbg_err_if((c = io_transfer(io, io->rbuf, &sz, 
00493             io->ubuf + io->uoff, io->ucount)) < 0);
00494         dbg_err_if(c < 0);
00495         dbg_err_if(c == 0 && sz == 0);
00496         io->ucount -= c;
00497         if(io->ucount == 0)
00498             io->uoff = 0;
00499         else
00500             io->uoff += c;
00501 
00502         io->rcount = sz;
00503         io->roff = 0;
00504     }
00505 
00506     return io->rcount;
00507 err:
00508     return -1;
00509 }
00510 
00525 ssize_t io_read(io_t *io, char *buf, size_t size)
00526 {
00527     char *out = buf;
00528     size_t wr;
00529     ssize_t c;
00530 
00531     dbg_err_if (io == NULL);
00532     dbg_err_if (buf == NULL);
00533     
00534     if(io->eof)
00535         return 0;
00536 
00537     while(size)
00538     {
00539         if(io->rcount == 0)
00540         {
00541             dbg_err_if((c = io_underflow(io)) < 0);
00542             if(c == 0)
00543                 break;
00544         }
00545         /* copy out data */
00546         wr = MIN(io->rcount, size); 
00547         memcpy(out, io->rbuf + io->roff, wr);
00548         io->rcount -= wr;
00549         io->roff += wr;
00550         out += wr;
00551         size -= wr;
00552     }
00553 
00554     return out - buf;
00555 err:
00556     return -1;
00557 }
00558 
00572 ssize_t io_printf(io_t *io, const char *fmt, ...)
00573 {
00574     enum { BUFSZ = 2048 };
00575     char buf[BUFSZ], *bbuf = NULL; 
00576     va_list ap, ap2;
00577     int sz;
00578 
00579     dbg_err_if (io == NULL);
00580     dbg_err_if (fmt == NULL);
00581 
00582     /* build the message to print */
00583     va_start(ap, fmt); /* init variable list arguments */
00584 
00585     sz = vsnprintf(buf, BUFSZ, fmt, ap);
00586 
00587     va_end(ap);
00588 
00589     if(sz >= BUFSZ)
00590     { /* stack buffer too small, alloc a bigger one on the heap */
00591         va_start(ap2, fmt); /* don't know if ap can be reused... */
00592 
00593         bbuf = (char*)u_malloc(++sz);
00594         dbg_err_if(bbuf == NULL);
00595 
00596         if((sz = vsnprintf(bbuf, sz, fmt, ap2)) > 0)
00597         {
00598             dbg_err_if(io_write(io, bbuf, sz) < 0);
00599         }
00600 
00601         va_end(ap2);
00602 
00603         U_FREE(bbuf);
00604     } else if(sz > 0) {
00605         dbg_err_if(io_write(io, buf, sz) < 0);
00606     }
00607 
00608     return 0;
00609 err:
00610     return -1;
00611 }
00612 
00622 ssize_t io_flush(io_t *io)
00623 {
00624     ssize_t c;
00625     size_t off = 0;
00626 
00627     dbg_err_if (io == NULL);
00628  
00629     while(io->wcount)
00630     {
00631         c = io->write(io, io->wbuf + off, io->wcount);
00632         dbg_err_if(c < 0);
00633         if(c == 0)
00634             break;
00635     
00636         io->wcount -= c;
00637         off += c;
00638     }
00639 
00640     return 0;
00641 err:
00642     return -1;
00643 }
00644 
00656 ssize_t io_write(io_t *io, const char *buf, size_t size)
00657 {
00658     size_t sz = 0, rem = size;
00659     ssize_t c = 0;
00660 
00661     dbg_err_if (io == NULL);
00662     dbg_err_if (buf == NULL);
00663     
00664     if(io->wbuf == NULL)
00665         dbg_err_if(io_wbuf_alloc(io)); /* alloc the write buffer */
00666 
00667     while(rem)
00668     {
00669         if(IO_WBUF_FULL(io)) /* if there's no more free space */
00670             dbg_err_if(io_flush(io));
00671 
00672         sz = IO_WBUF_AVAIL(io);
00673         c = io_transfer(io, io->wbuf + io->wcount, &sz, buf, rem);
00674         dbg_err_if(c < 0);
00675         dbg_err_if(c == 0 && sz == 0); /* some bytes MUST be read or written */
00676 
00677         io->wcount += sz;
00678         buf += c;
00679         rem -= c;
00680     }
00681 
00682     return size;
00683 err:
00684     return -1;
00685 }
00686 
00697 inline ssize_t io_putc(io_t *io, char c)
00698 {
00699     return io_write(io, &c, 1);
00700 }
00701 
00712 inline ssize_t io_getc(io_t *io, char *pc)
00713 {
00714     return io_read(io, pc, 1);
00715 }
00716 
00717 static inline char *io_strnchr(char *buf, size_t sz, char c)
00718 {
00719     register char *p;
00720 
00721     dbg_goto_if (buf == NULL, end);
00722 
00723     p = buf;
00724 
00725     while(sz--)
00726     {
00727         if(*p == c)
00728             return p;
00729         ++p;
00730     }
00731 end:
00732     return NULL;
00733 }
00734 
00747 ssize_t io_gets(io_t *io, char *buf, size_t size)
00748 {
00749     ssize_t wr, c, len = 0;
00750     char *p;
00751 
00752     dbg_err_if (io == NULL);
00753     dbg_err_if (buf == NULL);
00754 
00755     if(size < 2)
00756         return -1; /* buf too small */
00757 
00758     --size; /* save a char for \0 */
00759 
00760     if(io->rcount == 0)
00761         dbg_err_if(io_underflow(io) < 0);
00762 
00763     if(io->rcount == 0)
00764         return 0;
00765 
00766     for(;;)
00767     {
00768         if((p = io_strnchr(io->rbuf + io->roff, io->rcount, '\n')) != NULL)
00769         {
00770             p++; /* jump over newline */
00771             wr = MIN(p - (io->rbuf + io->roff), size);
00772             memcpy(buf, io->rbuf + io->roff, wr);
00773             buf[wr] = 0;
00774             io->rcount -= wr;
00775             io->roff += wr;
00776             len += wr;
00777             break;
00778         } else {
00779             if(size >= io->rcount)
00780             {
00781                 memcpy(buf, io->rbuf + io->roff, io->rcount);
00782                 len += io->rcount;
00783                 buf += io->rcount;
00784                 size -= io->rcount;
00785                 io->rcount = 0;
00786                 io->roff = 0;
00787                 dbg_err_if((c = io_underflow(io)) < 0);
00788                 if(c == 0)
00789                     break;
00790             } else {
00791                 /* buffer too small, return a partial line */
00792                 memcpy(buf, io->rbuf + io->roff, size);
00793                 len += size;
00794                 io->rcount -= size;
00795                 io->roff += size;
00796                 break;
00797             }
00798         }
00799     }
00800 
00801     buf[len] = 0;
00802     return len; /* return the # of chars in the line (strlen(line)) */
00803 err:
00804     return -1;
00805 }
00806 
00815 int io_codec_add_head(io_t *io, codec_t* c)
00816 {
00817     dbg_return_if (io == NULL, ~0);
00818     dbg_return_if (c == NULL, ~0);
00819 
00820     /* insert the codec at the head of the chain */
00821     TAILQ_INSERT_HEAD(&io->codec_chain, c, np);
00822 
00823     return 0;
00824 }
00825 
00834 int io_codec_add_tail(io_t *io, codec_t* c)
00835 {
00836     dbg_return_if (io == NULL, ~0);
00837     dbg_return_if (c == NULL, ~0);
00838 
00839     /* insert the codec at the end of the chain */
00840     TAILQ_INSERT_TAIL(&io->codec_chain, c, np);
00841 
00842     return 0;
00843 }
00844 
00852 int io_codecs_remove(io_t *io)
00853 {
00854     codec_t *codec;
00855     int rc = 0;
00856 
00857     dbg_return_if (io == NULL, ~0);
00858 
00859     if(!TAILQ_EMPTY(&io->codec_chain))
00860     {
00861         if(io->wbuf)
00862             dbg_ifb(io_chain_flush(io))
00863                 rc++;
00864 
00865         while((codec = TAILQ_FIRST(&io->codec_chain)) != NULL)
00866         {
00867             TAILQ_REMOVE(&io->codec_chain, codec, np);
00868             codec_free(codec);
00869         }
00870     }
00871 
00872     return rc;
00873 }
00874 
00886 int io_name_set(io_t *io, const char *name)
00887 {
00888     char *n;
00889 
00890     dbg_err_if (io == NULL);
00891     dbg_err_if (name == NULL);
00892     
00893     n = u_strdup(name);
00894     dbg_err_if(n == NULL);
00895 
00896     U_FREE(io->name);
00897 
00898     io->name = n;
00899 
00900     return 0;
00901 err:
00902     return ~0;
00903 }
00904 
00916 int io_name_get(io_t *io, char *name, size_t sz)
00917 {
00918     size_t min = 0;
00919 
00920     dbg_err_if (io == NULL);
00921     dbg_err_if (io->name == NULL);
00922     dbg_err_if (name == NULL);
00923     dbg_err_if (sz < 2);
00924 
00925     min = MIN(sz-1, strlen(io->name));
00926 
00927     memcpy(name, io->name, min);
00928     name[min] = 0;
00929     
00930     return 0;
00931 err:
00932     return ~0;
00933 }
00934 
00935 /*
00936  * \brief   Return the secure state of the IO object
00937  *  
00938  *  Return 0 if the connection is not secure (i.e. not encrypted) or not zero
00939  *  otherwise
00940  *
00941  * \param io    io object
00942  *
00943  * \return \c 0 for not secure connections, non-zero otherwise
00944  */
00945 int io_is_secure(io_t *io)
00946 {
00947     dbg_err_if(io == NULL);
00948 
00949     return io->is_secure;
00950 err:
00951     return 0;
00952 }
00953 
00954 
00955 /* used by io devices init functions: alloc (used dev_sz block size) 
00956    and initialize an io_t */
00957 int io_prv_create(size_t dev_sz, io_t **pio)
00958 {
00959     io_t *io = NULL;
00960 
00961     dbg_err_if (pio == NULL);
00962 
00963     io = u_zalloc(dev_sz);
00964     dbg_err_if(io == NULL);
00965 
00966     TAILQ_INIT(&io->codec_chain);
00967 
00968     /* set refcnt to 1 */
00969     io->refcnt++;
00970 
00971     /* size of the io device struct (that's also a 'castable' io_t) */
00972     io->size = dev_sz;
00973 
00974     *pio = io;
00975 
00976     return 0;
00977 err:
00978     U_FREE(io);
00979     return -1;
00980 }
00981 

←Products
© 2005-2006 - KoanLogic S.r.l. - All rights reserved