Back to index

avfs  1.0.1
avfs_server.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 1998-2001  Miklos Szeredi <miklos@szeredi.hu>
00004 
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 */
00008 
00009 #include "server.h"
00010 #include "cmd.h"
00011 #include "send.h"
00012 #include "internal.h"
00013 #include "operutil.h"
00014 #include "oper.h"
00015 
00016 #include <stdlib.h>
00017 #include <unistd.h>
00018 #include <fcntl.h>
00019 #include <sys/socket.h>
00020 #include <poll.h>
00021 #include <assert.h>
00022 
00023 #define MULTITHREADED 1
00024 
00025 #if MULTITHREADED
00026 #include <pthread.h>
00027 #endif
00028 
00029 enum file_holder_state {
00030     FIH_DELETED = -1,
00031     FIH_UNUSED = 0,
00032     FIH_USED = 1,
00033 };
00034 
00035 struct file_holder {
00036     enum file_holder_state state;
00037     int serverfh;
00038 };
00039 
00040 static struct file_holder *file_holders;
00041 static unsigned int file_holder_num;
00042 static AV_LOCK_DECL(file_holder_lock);
00043 
00044 struct cmdinfo {
00045     int fd;
00046     struct avfs_in_message inmsg;
00047     struct avfs_cmd cmd;
00048 };
00049 
00050 static void init_inmsg(struct avfs_in_message *inmsg)
00051 {
00052     int i;
00053 
00054     for(i = 1; i < MAXSEG; i++)
00055         inmsg->seg[i].buf = NULL;
00056 }
00057 
00058 static void free_inmsg(struct avfs_in_message *inmsg)
00059 {
00060     int i;
00061 
00062     for(i = 1; i < MAXSEG; i++) {
00063         if(inmsg->seg[i].buf)
00064             free(inmsg->seg[i].buf);
00065     }
00066 }
00067 
00068 static int entry_local(ventry *ve)
00069 {
00070     if(ve->mnt->base == NULL)
00071         return 1;
00072     else
00073         return 0;
00074 }
00075 
00076 
00077 static int getattr_entry(ventry *ve, struct avstat *stbuf, int attrmask,
00078                          int flags)
00079 {
00080     int res;
00081     vfile vf;
00082     
00083     res = av_file_open(&vf, ve, AVO_NOPERM | flags, 0);
00084     if(res == 0) {
00085         res = av_file_getattr(&vf, stbuf, attrmask);
00086         av_file_close(&vf);
00087     }
00088 
00089     return res;
00090 }
00091 
00092 static void send_error(int fd, int error)
00093 {
00094     int res;
00095     struct avfs_out_message outmsg;
00096     struct avfs_result result;
00097     
00098     outmsg.num = 1;
00099     outmsg.seg[0].len = sizeof(result);
00100     outmsg.seg[0].buf = &result;
00101     
00102     result.result = error;
00103     res = __av_write_message(fd, &outmsg);
00104     if(res == -1)
00105         av_log(AVLOG_ERROR, "Error sending message\n");
00106 }
00107 
00108 static int do_readdir(int fd, struct avfs_direntry *de, char *name)
00109 {
00110     int res;
00111     struct avdirent buf;
00112     avoff_t n;
00113     
00114     res = av_fd_readdir(fd, &buf, &n);
00115     if(res > 0) {
00116         de->ino = buf.ino;
00117         de->type = buf.type;
00118         de->n = n;
00119         strncpy(name, buf.name, NAME_MAX);
00120         name[NAME_MAX] = '\0';
00121         av_free(buf.name);
00122     }
00123 
00124     return res;
00125 }
00126 
00127 static void process_getattr(struct cmdinfo *ci)
00128 {
00129     int res;
00130     char *path = ci->inmsg.seg[1].buf;
00131     int flags = ci->cmd.u.getattr.flags;
00132     int attrmask = ci->cmd.u.getattr.attrmask;
00133     struct avstat stbuf;
00134     ventry *ve;
00135     struct avfs_out_message outmsg;
00136     struct avfs_result result;
00137 
00138     av_log(AVLOG_SYSCALL, "getattr(\"%s\", 0%o, 0%o)",
00139              path, flags, attrmask);
00140     
00141     outmsg.num = 3;
00142     outmsg.seg[0].len = sizeof(result);
00143     outmsg.seg[0].buf = &result;
00144     outmsg.seg[1].len = 0;
00145     outmsg.seg[2].len = 0;
00146 
00147     res = av_get_ventry(path, !(flags & AVO_NOFOLLOW), &ve);
00148     if(res < 0)
00149         result.result = res;
00150     else {
00151         if(entry_local(ve)) {
00152             result.result = -EPERM;
00153             outmsg.seg[1].buf = (char *) ve->data;
00154             outmsg.seg[1].len = strlen(outmsg.seg[1].buf) + 1;
00155             if(outmsg.seg[1].len > PATHBUF_LEN) {
00156                 outmsg.seg[1].len = 0;
00157                 result.result = -ENAMETOOLONG;
00158             }
00159         }
00160         else {
00161             res = getattr_entry(ve, &stbuf, attrmask, flags);
00162             result.result = res;
00163             if(res == 0) {
00164                 outmsg.seg[2].buf = &stbuf;
00165                 outmsg.seg[2].len = sizeof(stbuf);
00166             }
00167         }
00168     }
00169 
00170     av_log(AVLOG_SYSCALL, "   getattr(\"%s\", 0%o, 0%o) = %i (%s)",
00171              path, flags, attrmask, result.result,
00172              outmsg.seg[1].len ? (char *) ve->data : "");
00173 
00174     res = __av_write_message(ci->fd, &outmsg);
00175     if(res == -1)
00176         av_log(AVLOG_ERROR, "Error sending message\n");
00177 
00178     av_free_ventry(ve);    
00179 }
00180 
00181 static void register_holder(int holderfd, int serverfh)
00182 {
00183     int needclose = 0;
00184     int state;
00185 
00186     AV_LOCK(file_holder_lock);
00187     state = file_holders[holderfd].state;
00188 
00189     av_log(AVLOG_DEBUG, "register_holder: %i, state: %i/%i, serverfh: %i",
00190              holderfd, state,  file_holders[holderfd].serverfh, serverfh);
00191     
00192     if(state == FIH_USED) {
00193         if(serverfh < 0)
00194             file_holders[holderfd].state = FIH_UNUSED;
00195         else
00196             file_holders[holderfd].serverfh = serverfh;
00197     }
00198     else {
00199         if(serverfh >= 0)
00200             needclose = 1;
00201 
00202         file_holders[holderfd].state = FIH_UNUSED;
00203         close(holderfd);
00204     }
00205     AV_UNLOCK(file_holder_lock);
00206 
00207     if(needclose)
00208         av_fd_close(serverfh);
00209 }
00210 
00211 static void process_open(struct cmdinfo *ci)
00212 {
00213     int res;
00214     char *path = ci->inmsg.seg[1].buf;
00215     int flags = ci->cmd.u.open.flags;
00216     mode_t mode = ci->cmd.u.open.mode;
00217     ventry *ve;
00218     struct avfs_out_message outmsg;
00219     struct avfs_result result;
00220 
00221     av_log(AVLOG_SYSCALL, "open(\"%s\", 0%o, 0%lo)", path, flags,
00222            (unsigned long) mode);
00223     
00224     outmsg.num = 2;
00225     outmsg.seg[0].len = sizeof(result);
00226     outmsg.seg[0].buf = &result;
00227     outmsg.seg[1].len = 0;
00228 
00229     res = av_get_ventry(path, 1, &ve);
00230     if(res < 0)
00231         result.result = res;
00232     else {
00233         if(entry_local(ve)) {
00234             result.result = -EPERM;
00235             outmsg.seg[1].buf = (char *) ve->data;
00236             outmsg.seg[1].len = strlen(outmsg.seg[1].buf) + 1;
00237             if(outmsg.seg[1].len > PATHBUF_LEN) {
00238                 outmsg.seg[1].len = 0;
00239                 result.result = -ENAMETOOLONG;
00240             }
00241         }
00242         else {
00243             struct avstat stbuf;
00244 
00245             res = getattr_entry(ve, &stbuf, AVA_MODE, 0);
00246             if(res == 0) {
00247                 if(AV_ISDIR(stbuf.mode))
00248                     res = av_fd_open_entry(ve, flags | AVO_DIRECTORY, mode);
00249                 else
00250                     res = av_fd_open_entry(ve, flags, mode);
00251             }
00252             else if(res == -ENOENT && (flags & AVO_CREAT) != 0)
00253                 res = av_fd_open_entry(ve, flags, mode);
00254 
00255             result.result = res;
00256         }
00257     }
00258     av_log(AVLOG_SYSCALL, "   open(\"%s\", 0%o, 0%lo) = %i (%s)",
00259              path, flags, (unsigned long) mode, result.result,
00260              outmsg.seg[1].len ? (char *) ve->data : "");
00261 
00262     register_holder(ci->fd, result.result);
00263 
00264     res = __av_write_message(ci->fd, &outmsg);
00265     if(res == -1)
00266         av_log(AVLOG_ERROR, "Error sending message\n");
00267 
00268     av_free_ventry(ve);    
00269 }
00270 
00271 
00272 static void process_close(struct cmdinfo *ci)
00273 {
00274     int res;
00275     int fh = ci->cmd.u.fdops.serverfh;
00276     struct avfs_out_message outmsg;
00277     struct avfs_result result;
00278 
00279     av_log(AVLOG_SYSCALL, "close(%i)", fh);
00280     
00281     outmsg.num = 1;
00282     outmsg.seg[0].len = sizeof(result);
00283     outmsg.seg[0].buf = &result;
00284 
00285     result.result = av_fd_close(fh);
00286     av_log(AVLOG_SYSCALL, "   close(%i) = %i", fh, result.result);
00287 
00288     res = __av_write_message(ci->fd, &outmsg);
00289     if(res == -1)
00290         av_log(AVLOG_ERROR, "Error sending message\n");
00291 }
00292 
00293 static void process_fstat(struct cmdinfo *ci)
00294 {
00295     int res;
00296     int fh = ci->cmd.u.fdops.serverfh;
00297     struct avfs_out_message outmsg;
00298     struct avfs_result result;
00299     struct avstat stbuf;
00300 
00301     av_log(AVLOG_SYSCALL, "fstat(%i)", fh);
00302     
00303     outmsg.num = 2;
00304     outmsg.seg[0].len = sizeof(result);
00305     outmsg.seg[0].buf = &result;
00306     outmsg.seg[1].len = 0;
00307 
00308     result.result = av_fd_getattr(fh, &stbuf, AVA_ALL);
00309     if(result.result == 0) {
00310         outmsg.seg[1].len = sizeof(stbuf);
00311         outmsg.seg[1].buf = &stbuf;
00312     }
00313 
00314     av_log(AVLOG_SYSCALL, "   fstat(%i) = %i", fh, result.result);
00315 
00316     res = __av_write_message(ci->fd, &outmsg);
00317     if(res == -1)
00318         av_log(AVLOG_ERROR, "Error sending message\n");
00319 }
00320 
00321 static void process_readdir(struct cmdinfo *ci)
00322 {
00323     int res;
00324     int fh = ci->cmd.u.fdops.serverfh;
00325     struct avfs_out_message outmsg;
00326     struct avfs_result result;
00327     char name[NAME_MAX + 1];
00328     struct avfs_direntry de;
00329 
00330     av_log(AVLOG_SYSCALL, "readdir(%i, ...)", fh);
00331     
00332     outmsg.num = 3;
00333     outmsg.seg[0].len = sizeof(result);
00334     outmsg.seg[0].buf = &result;
00335     outmsg.seg[1].len = 0;
00336     outmsg.seg[2].len = 0;
00337 
00338     result.result = do_readdir(fh, &de, name);
00339     if(result.result > 0) {
00340         outmsg.seg[1].len = sizeof(de);
00341         outmsg.seg[1].buf = &de;
00342         outmsg.seg[2].len = strlen(name) + 1;
00343         outmsg.seg[2].buf = name;
00344     }
00345 
00346     av_log(AVLOG_SYSCALL, "   readdir(%i, {%s, %lli, %i}) = %i",
00347              fh, result.result > 0 ? name : "", de.ino, de.n, result.result);
00348 
00349     res = __av_write_message(ci->fd, &outmsg);
00350     if(res == -1)
00351         av_log(AVLOG_ERROR, "Error sending message\n");
00352 }
00353 
00354 static void process_lseek(struct cmdinfo *ci)
00355 {
00356     int res;
00357     int fh = ci->cmd.u.lseek.serverfh;
00358     avoff_t offset = ci->cmd.u.lseek.offset;
00359     int whence = ci->cmd.u.lseek.whence;
00360     struct avfs_out_message outmsg;
00361     struct avfs_result result;
00362 
00363     av_log(AVLOG_SYSCALL, "lseek(%i, %lli, %i)", fh, offset, whence);
00364     
00365     outmsg.num = 1;
00366     outmsg.seg[0].len = sizeof(result);
00367     outmsg.seg[0].buf = &result;
00368 
00369     result.u.lseek.offset = av_fd_lseek(fh, offset, whence);
00370 
00371     av_log(AVLOG_SYSCALL, "   lseek(%i, %lli, %i) == %lli",
00372              fh, offset, whence, result.u.lseek.offset);
00373 
00374     res = __av_write_message(ci->fd, &outmsg);
00375     if(res == -1)
00376         av_log(AVLOG_ERROR, "Error sending message\n");
00377 }
00378 
00379 static void process_read(struct cmdinfo *ci)
00380 {
00381     int res;
00382     int fh = ci->cmd.u.readwrite.serverfh;
00383     avsize_t nbyte = ci->cmd.u.readwrite.nbyte;
00384     struct avfs_out_message outmsg;
00385     struct avfs_result result;
00386     void *buf;
00387         
00388     outmsg.num = 2;
00389     outmsg.seg[0].len = sizeof(result);
00390     outmsg.seg[0].buf = &result;
00391     outmsg.seg[1].len = 0;
00392     
00393     buf = av_malloc(nbyte);
00394 
00395     result.result = av_fd_read(fh, buf, nbyte);
00396     if(result.result > 0) {
00397         outmsg.seg[1].len = result.result;
00398         outmsg.seg[1].buf = buf;
00399     }
00400    
00401     res = __av_write_message(ci->fd, &outmsg);
00402     if(res == -1)
00403         av_log(AVLOG_ERROR, "Error sending message\n");
00404 
00405     av_free(buf);
00406 }
00407 
00408 static void process_write(struct cmdinfo *ci)
00409 {
00410     int res;
00411     int fh = ci->cmd.u.readwrite.serverfh;
00412     avsize_t nbyte = ci->cmd.u.readwrite.nbyte;
00413     struct avfs_out_message outmsg;
00414     struct avfs_result result;
00415     const void *buf = ci->inmsg.seg[1].buf;
00416 
00417     av_log(AVLOG_SYSCALL, "write(%i, ..., %u)", fh, nbyte);
00418     
00419     outmsg.num = 1;
00420     outmsg.seg[0].len = sizeof(result);
00421     outmsg.seg[0].buf = &result;
00422     
00423     result.result = av_fd_write(fh, buf, nbyte);
00424    
00425     av_log(AVLOG_SYSCALL, "   write(%i, ..., %u) = %i",
00426              fh, nbyte, result.result);
00427 
00428 
00429     res = __av_write_message(ci->fd, &outmsg);
00430     if(res == -1)
00431         av_log(AVLOG_ERROR, "Error sending message\n");
00432 }
00433 
00434 
00435 static void process_resolve(struct cmdinfo *ci)
00436 {
00437     int res;
00438     char *path = ci->inmsg.seg[1].buf;
00439     ventry *ve;
00440     struct avfs_out_message outmsg;
00441     struct avfs_result result;
00442     char *newpath = NULL;
00443     
00444     av_log(AVLOG_SYSCALL, "resolve(\"%s\")", path);
00445     
00446     outmsg.num = 2;
00447     outmsg.seg[0].len = sizeof(result);
00448     outmsg.seg[0].buf = &result;
00449     outmsg.seg[1].len = 0;
00450 
00451     res = av_get_ventry(path, 1, &ve);
00452     if(res < 0)
00453         result.result = res;
00454     else {
00455         if(entry_local(ve))
00456             result.u.resolve.isvirtual = 0;
00457         else
00458             result.u.resolve.isvirtual = 1;
00459 
00460         res = av_generate_path(ve, &newpath);
00461         result.result = res;
00462         if(res == 0) {
00463             outmsg.seg[1].buf = newpath;
00464             outmsg.seg[1].len = strlen(outmsg.seg[1].buf) + 1;
00465             if(outmsg.seg[1].len > PATHBUF_LEN) {
00466                 outmsg.seg[1].len = 0;
00467                 result.result = -ENAMETOOLONG;
00468             }
00469         }
00470         av_free_ventry(ve);    
00471     }
00472 
00473     av_log(AVLOG_SYSCALL, "   resolve(\"%s\", \"%s\", %i) = %i",
00474              path, outmsg.seg[1].len ? newpath : "", 
00475              result.u.resolve.isvirtual, result.result);
00476 
00477     res = __av_write_message(ci->fd, &outmsg);
00478     if(res == -1)
00479         av_log(AVLOG_ERROR, "Error sending message\n");
00480     
00481     av_free(newpath);
00482 }
00483 
00484 static void process_readlink(struct cmdinfo *ci)
00485 {
00486     int res;
00487     char *path = ci->inmsg.seg[1].buf;
00488     avsize_t bufsize = ci->cmd.u.readlink.bufsize;
00489     char *buf = NULL;
00490     ventry *ve;
00491     struct avfs_out_message outmsg;
00492     struct avfs_result result;
00493 
00494     av_log(AVLOG_SYSCALL, "readlink(\"%s\", ..., %u)", path, bufsize);
00495     
00496     outmsg.num = 3;
00497     outmsg.seg[0].len = sizeof(result);
00498     outmsg.seg[0].buf = &result;
00499     outmsg.seg[1].len = 0;
00500     outmsg.seg[2].len = 0;
00501 
00502     res = av_get_ventry(path, 0, &ve);
00503     if(res < 0)
00504         result.result = res;
00505     else {
00506         if(entry_local(ve)) {
00507             result.result = -EPERM;
00508             outmsg.seg[1].buf = (char *) ve->data;
00509             outmsg.seg[1].len = strlen(outmsg.seg[1].buf) + 1;
00510             if(outmsg.seg[1].len > PATHBUF_LEN) {
00511                 outmsg.seg[1].len = 0;
00512                 result.result = -ENAMETOOLONG;
00513             }
00514         }
00515         else {
00516             res = av_readlink(ve, &buf);
00517             if(res == 0) {
00518                 avsize_t linklen = strlen(buf);
00519 
00520                 result.result = AV_MIN(linklen, bufsize);
00521                 outmsg.seg[2].len = AV_MIN(linklen + 1, bufsize);
00522                 outmsg.seg[2].buf = buf;
00523             }
00524             else
00525                 result.result = res;
00526         }
00527     }
00528 
00529     av_log(AVLOG_SYSCALL, "   readlink(\"%s\", \"%.*s\", %i) = %i (%s)",
00530              path, 
00531              result.result < 0 ? 0 : result.result, buf == NULL ? "" : buf,
00532              bufsize, result.result, 
00533              outmsg.seg[1].len ? (char *) ve->data : "");
00534 
00535     res = __av_write_message(ci->fd, &outmsg);
00536     if(res == -1)
00537         av_log(AVLOG_ERROR, "Error sending message\n");
00538 
00539     av_free_ventry(ve);    
00540     av_free(buf);
00541 }
00542 
00543 static void process_access(struct cmdinfo *ci)
00544 {
00545     int res;
00546     char *path = ci->inmsg.seg[1].buf;
00547     int amode = ci->cmd.u.access.amode;
00548     ventry *ve;
00549     struct avfs_out_message outmsg;
00550     struct avfs_result result;
00551 
00552     av_log(AVLOG_SYSCALL, "access(\"%s\", 0%o)", path, amode);
00553     
00554     outmsg.num = 2;
00555     outmsg.seg[0].len = sizeof(result);
00556     outmsg.seg[0].buf = &result;
00557     outmsg.seg[1].len = 0;
00558 
00559     res = av_get_ventry(path, 1, &ve);
00560     if(res < 0)
00561         result.result = res;
00562     else {
00563         if(entry_local(ve)) {
00564             result.result = -EPERM;
00565             outmsg.seg[1].buf = (char *) ve->data;
00566             outmsg.seg[1].len = strlen(outmsg.seg[1].buf) + 1;
00567             if(outmsg.seg[1].len > PATHBUF_LEN) {
00568                 outmsg.seg[1].len = 0;
00569                 result.result = -ENAMETOOLONG;
00570             }
00571         }
00572         else
00573             result.result =  av_access(ve, amode);
00574     }
00575 
00576     av_log(AVLOG_SYSCALL, "   access(\"%s\", 0%o) = %i (%s)",
00577            path, amode, result.result, 
00578            outmsg.seg[1].len ? (char *) ve->data : "");
00579 
00580     res = __av_write_message(ci->fd, &outmsg);
00581     if(res == -1)
00582         av_log(AVLOG_ERROR, "Error sending message\n");
00583 
00584     av_free_ventry(ve);    
00585 }
00586 
00587 
00588 static void *process_message(void *arg)
00589 {
00590     struct cmdinfo *ci = (struct cmdinfo *) arg;
00591     
00592     switch(ci->cmd.type) {
00593     case CMD_GETATTR:
00594         process_getattr(ci);
00595         break;
00596         
00597     case CMD_OPEN:
00598         process_open(ci);
00599         break;
00600         
00601     case CMD_CLOSE:
00602         process_close(ci);
00603         break;
00604         
00605     case CMD_FSTAT:
00606         process_fstat(ci);
00607         break;
00608         
00609     case CMD_READDIR:
00610         process_readdir(ci);
00611         break;
00612         
00613     case CMD_LSEEK:
00614         process_lseek(ci);
00615         break;
00616         
00617     case CMD_READ:
00618         process_read(ci);
00619         break;
00620 
00621     case CMD_WRITE:
00622         process_write(ci);
00623         break;
00624         
00625     case CMD_RESOLVE:
00626         process_resolve(ci);
00627         break;
00628         
00629     case CMD_READLINK:
00630         process_readlink(ci);
00631         break;
00632 
00633     case CMD_ACCESS:
00634         process_access(ci);
00635         break;
00636         
00637     default:
00638         av_log(AVLOG_ERROR, "Unknown command: %i", ci->cmd.type);
00639         send_error(ci->fd, -ENOSYS);
00640     }
00641 
00642     if(ci->cmd.type != CMD_OPEN)
00643         close(ci->fd);
00644     free_inmsg(&ci->inmsg);
00645     av_free(ci);
00646 
00647     return NULL;
00648 }
00649 
00650 static void mark_file_holder(int holderfd)
00651 {
00652     AV_LOCK(file_holder_lock);
00653     if(holderfd >= file_holder_num) {
00654         int i;
00655         unsigned int newnum = holderfd + 1;
00656         unsigned int newsize = newnum  * sizeof(struct file_holder);
00657 
00658         file_holders = realloc(file_holders, newsize);
00659         assert(file_holders != NULL);
00660 
00661         for(i = file_holder_num; i <= holderfd; i++)
00662             file_holders[i].state = FIH_UNUSED;
00663 
00664         file_holder_num = newnum;
00665     }
00666     
00667     if(file_holders[holderfd].state != FIH_UNUSED)
00668         av_log(AVLOG_ERROR, "Internal Error: file holder %i already used",
00669                  holderfd);
00670 
00671     file_holders[holderfd].state = FIH_USED;
00672     file_holders[holderfd].serverfh = -1;
00673     
00674     AV_UNLOCK(file_holder_lock);
00675 }
00676 
00677 static void unmark_file_holder(int serverfh)
00678 {
00679     int i;
00680 
00681     AV_LOCK(file_holder_lock);
00682     for(i = 0; i < file_holder_num; i++) {
00683         if(file_holders[i].state == FIH_USED &&
00684            file_holders[i].serverfh == serverfh) {
00685             file_holders[i].state = FIH_UNUSED;
00686             close(i);
00687             break;
00688         }
00689     }
00690     if(i == file_holder_num)
00691         av_log(AVLOG_DEBUG, "File holder not found for %i", serverfh);
00692 
00693     AV_UNLOCK(file_holder_lock);    
00694 }
00695 
00696 static int wait_message(int sock)
00697 {
00698     int i;
00699     int nfds;
00700     struct pollfd *fds;
00701     int canaccept;
00702     int res;
00703 
00704     while(1) {
00705         AV_LOCK(file_holder_lock);
00706         nfds = 1;
00707         for(i = 0; i < file_holder_num; i++) {
00708             if(file_holders[i].state == FIH_USED)
00709                 nfds++;
00710         }
00711         /* This is not av_malloc(), because exit will usually happen
00712            during poll(), and then there would be one unfreed memory. */
00713         fds = malloc(sizeof(struct pollfd) * nfds);
00714         nfds = 1;
00715         for(i = 0; i < file_holder_num; i++) {
00716             if(file_holders[i].state == FIH_USED) {
00717                 fds[nfds].fd = i;
00718                 fds[nfds].events = POLLIN;
00719                 nfds++;
00720             }
00721         }
00722         AV_UNLOCK(file_holder_lock);
00723         fds[0].fd = sock;
00724         fds[0].events = POLLIN;
00725         
00726         do res = poll(fds, nfds, -1);
00727         while(res == -1 && (errno == EAGAIN || errno == EINTR));
00728 
00729         if(res == -1) {
00730             av_log(AVLOG_ERROR, "poll(): %s", strerror(errno));
00731             exit(1);
00732         }
00733 
00734         for(i = 1; i < nfds; i++) {
00735             if(fds[i].revents != 0) {
00736                 int holderfd = fds[i].fd;
00737                 int serverfh;
00738 
00739                 AV_LOCK(file_holder_lock);
00740                 serverfh = file_holders[holderfd].serverfh;
00741 
00742                 {
00743                     char c;
00744                     av_log(AVLOG_DEBUG, "File holder closed: %i", holderfd);
00745                     av_log(AVLOG_DEBUG, "serverfh: %i", serverfh);
00746                     av_log(AVLOG_DEBUG, "state: %i",
00747                              file_holders[holderfd].state);
00748                     av_log(AVLOG_DEBUG, "revents: 0%o", fds[i].revents);
00749                     res = read(holderfd, &c, 1);
00750                     av_log(AVLOG_DEBUG, "read: %i, (%i)", res, c);
00751                 }
00752                 
00753                 if(file_holders[holderfd].state == FIH_USED) {
00754                     if(serverfh == -1)
00755                         file_holders[holderfd].state = FIH_DELETED;
00756                     else {
00757                         close(holderfd);
00758                         file_holders[holderfd].state = FIH_UNUSED;
00759                     }
00760                 }
00761                 else 
00762                     close(holderfd);
00763 
00764                 AV_UNLOCK(file_holder_lock);
00765 
00766                 av_log(AVLOG_DEBUG, "File holder for %i closed", serverfh);
00767                                 
00768                 if(serverfh != -1)
00769                     av_fd_close(serverfh);
00770             }
00771         }
00772 
00773         canaccept = fds[0].revents;
00774 
00775         free(fds);
00776         
00777         if(canaccept) {
00778             int fd;
00779 
00780             fd = accept(sock, NULL, NULL);
00781             if(fd == -1) {
00782                 av_log(AVLOG_ERROR, "accept(): %s", strerror(errno));
00783                 exit(1);
00784             }
00785 
00786             return fd;
00787         }
00788     }
00789 }
00790 
00791 int main()
00792 {
00793     int sock;
00794 
00795 #if MULTITHREADED
00796     pthread_attr_t attr;
00797     pthread_t thrid;
00798 
00799     pthread_attr_init(&attr);
00800     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00801 #endif
00802 
00803     sock = server_init();
00804 
00805     while(1) {
00806         int fd;
00807         int res;
00808         struct cmdinfo *ci;
00809 
00810         fd = wait_message(sock);
00811         
00812         AV_NEW(ci);
00813         init_inmsg(&ci->inmsg);
00814         ci->inmsg.seg[0].buf = &ci->cmd;
00815 
00816         res = __av_read_message(fd, &ci->inmsg);
00817         if(res == -1)
00818             av_log(AVLOG_ERROR, "Error reading message");
00819         else {
00820             ci->fd = fd;
00821 
00822             if(ci->cmd.type == CMD_OPEN)
00823                 mark_file_holder(ci->fd);
00824             else if(ci->cmd.type == CMD_CLOSE)
00825                 unmark_file_holder(ci->cmd.u.fdops.serverfh);
00826             
00827 #if MULTITHREADED
00828             res = pthread_create(&thrid, &attr, process_message, ci);
00829             if(res != 0) 
00830                 av_log(AVLOG_ERROR, "Error creating thread: %i",
00831                          res);
00832 #else
00833             process_message(ci);
00834 #endif
00835         }
00836     }
00837     
00838     return 0;
00839 }
00840