mrecv.c
86badd32
 #include "makuosan.h"
 
634a23d7
 static void mrecv_req(mdata *data, struct sockaddr_in *addr);
 static void mrecv_ack(mdata *data, struct sockaddr_in *addr);
 
 /******************************************************************
 *
 * Receive common functions (private)
 *
 *******************************************************************/
86badd32
 static mfile *mrecv_mfdel(mfile *m)
 {
   mfile *r;
   if(!m)
     return(NULL);
   r = m->next;
   if(m->fd != -1){
     close(m->fd);
     m->fd = -1;
     if(S_ISREG(m->fs.st_mode))
       mremove(moption.base_dir, m->tn);
   }
   if(m->mark){
     free(m->mark);
     m->mark = NULL;
   }
   mfdel(m);
   return(r);
 }
 
634a23d7
 static int mrecv_decrypt(mdata *data, struct sockaddr_in *addr)
 {
   int i;
   MD5_CTX ctx;
   uint8_t hash[16];
 
   if(data->head.flags & MAKUO_FLAG_CRYPT){
     if(!moption.cryptena){
8f9aeac1
       lprintf(0, "%s: recv encrypt packet from %s. I have not key!", __func__, inet_ntoa(addr->sin_addr));
634a23d7
       return(-1);
     }
     if(data->head.szdata){
       for(i=0;i<data->head.szdata;i+=8){
         BF_decrypt((BF_LONG *)(data->data + i), &EncKey);
       }
       MD5_Init(&ctx);
       MD5_Update(&ctx, data->data, data->head.szdata);
       MD5_Final(hash, &ctx);
       if(memcmp(hash,data->head.hash,16)){
8f9aeac1
         lprintf(0, "%s: protocol checksum error from %s\n", __func__, inet_ntoa(addr->sin_addr));
634a23d7
         return(-1);
       }
     }
   }
   return(0);
 }
 
 static int mrecv_packet(int s, mdata *data, struct sockaddr_in *addr)
 {
   int recvsize;
   socklen_t addr_len;
 
   while(1){
     addr_len = sizeof(struct sockaddr_in);
     recvsize = recvfrom(s, data, sizeof(mdata), 0, (struct sockaddr *)addr, &addr_len);
     if(recvsize != -1){
       break;
     }else{
       if(errno == EAGAIN || errno == EINTR){
         continue;
       }else{
8f9aeac1
         lprintf(0, "%s: recv error from %s\n", __func__, inet_ntoa(addr->sin_addr));
634a23d7
         return(-1);
       }
     }
   }
   if(recvsize < sizeof(data->head)){
8f9aeac1
     lprintf(0, "%s: recv head size error\n", __func__);
634a23d7
     return(-1);
   }
 
   data->head.szdata = ntohs(data->head.szdata);
   data->head.flags  = ntohs(data->head.flags);
   data->head.reqid  = ntohl(data->head.reqid);
   data->head.seqno  = ntohl(data->head.seqno);
 
   if(data->head.vproto != PROTOCOL_VERSION){
8f9aeac1
     lprintf(0, "%s: protocol version error(%d != %d) from %s\n", __func__,
634a23d7
        data->head.vproto, PROTOCOL_VERSION, inet_ntoa(addr->sin_addr));
     return(-1);
   }
 
   return(mrecv_decrypt(data, addr));
 }
 
 /******************************************************************
 *
 * Receive common functions (public)
 *
 *******************************************************************/
 void mrecv(int s)
 {
   mdata  data;
   struct sockaddr_in addr;
   if(mrecv_packet(s, &data, &addr) == -1){
     return;
   }
   if(data.head.flags & MAKUO_FLAG_ACK){
     mrecv_ack(&data, &addr);
   }else{
     mrecv_req(&data, &addr);
   }
 }
 
 void mrecv_gc()
 {
   mhost *t = members;
   mfile *m = mftop[1]; 
 
   /* file timeout */
   while(m){
     if(mtimeout(&(m->lastrecv), MAKUO_RECV_GCWAIT)){
8f9aeac1
       lprintf(0,"%s: mfile object GC state=%d %s\n", __func__, m->mdata.head.nstate, m->fn);
634a23d7
       m = mrecv_mfdel(m);
       continue;
     }
     m = m->next;
   }
 
   /* pong timeout */
   while(t){
     if(!mtimeout(&(t->lastrecv), MAKUO_PONG_TIMEOUT)){
       t = t->next;
     }else{
8f9aeac1
       lprintf(0,"%s: pong timeout %s\n", __func__, t->hostname);
634a23d7
       if(t->next){
         t = t->next;
         member_del(t->prev);
       }else{
         member_del(t);
         t = NULL;
      } 
     }      
   }
 }
 
 /******************************************************************
 *
8f9aeac1
 * ack receive functions (for source node tasks)
634a23d7
 *
 *******************************************************************/
8f9aeac1
 static int mrecv_ack_search(mhost **lpt, mfile **lpm, mdata *data, struct sockaddr_in *addr)
634a23d7
 {
   mhost *t;
   mfile *m;
   *lpt = NULL;
   *lpm = NULL;
   t = member_add(&addr->sin_addr, NULL);
   if(!t){
8f9aeac1
     lprintf(0, "%s: member not found %s\n", __func__, inet_ntoa(addr->sin_addr));
     return(-1);
634a23d7
   }
   for(m=mftop[0];m;m=m->next)
     if(m->mdata.head.reqid == data->head.reqid)
       break;
   if(!m){
8f9aeac1
     lprintf(4, "%s: mfile not found rid=%06d state=%02d %s(%s)\n", __func__,
634a23d7
       data->head.reqid, data->head.nstate, inet_ntoa(addr->sin_addr), t->hostname);
8f9aeac1
     return(-1);
634a23d7
   }
   *lpt = t;
   *lpm = m;
8f9aeac1
   return(0);
634a23d7
 }
 
 static void mrecv_ack_report(mfile *m, mhost *h, mdata *data)
 {
   if(data->head.nstate == MAKUO_RECVSTATE_OPENERROR){
     cprintf(0, m->comm, "%s: file open error %s\n", h->hostname, m->fn);
8f9aeac1
     lprintf(0,          "%s: file open error rid=%06d state=%02d %s(%s) %s\n", __func__,
634a23d7
       data->head.reqid, data->head.nstate, inet_ntoa(h->ad), h->hostname, m->fn);
   }
   if(data->head.nstate == MAKUO_RECVSTATE_WRITEERROR){
     cprintf(0, m->comm, "%s: file write error %s\n", h->hostname, m->fn);
8f9aeac1
     lprintf(0,          "%s: file write error rid=%06d state=%02d %s(%s) %s\n", __func__,
634a23d7
      data->head.reqid, data->head.nstate, inet_ntoa(h->ad), h->hostname, m->fn);
   }
   if(data->head.nstate == MAKUO_RECVSTATE_CLOSEERROR){
     cprintf(0, m->comm, "%s: file close error %s\n", h->hostname, m->fn);
8f9aeac1
     lprintf(0,          "%s: file close error rid=%06d state=%02d %s(%s) %s\n", __func__,
634a23d7
       data->head.reqid, data->head.nstate, inet_ntoa(h->ad), h->hostname, m->fn);
   }
 }
 
 static void mrecv_ack_ping(mdata *data, struct sockaddr_in *addr)
 {
   member_add(&addr->sin_addr, data);
 }
 
 static void mrecv_ack_file(mdata *data, struct sockaddr_in *addr)
 {
   mhost *t;
   mfile *m;
 
8f9aeac1
   if(mrecv_ack_search(&t, &m, data, addr)){
     return;
   }
634a23d7
   mtimeget(&m->lastrecv);
   if(data->head.nstate == MAKUO_RECVSTATE_IGNORE){
     cprintf(4, m->comm, "%s: file update ignore %s\n", t->hostname, m->fn);
8f9aeac1
     lprintf(0,          "%s: file update ignore rid=%06d state=%02d %s(%s) %s\n", __func__, 
634a23d7
       data->head.reqid, data->head.nstate, inet_ntoa(t->ad), t->hostname, m->fn);
   }
   if(data->head.nstate == MAKUO_RECVSTATE_OPEN){
     uint32_t *d = (uint32_t *)(data->data);
     while(d < (uint32_t *)&data->data[data->head.szdata]){
       seq_addmark(m, *d, (*d) + 1);
       d++;
     }
   }
   t->state = data->head.nstate;
   mrecv_ack_report(m, t, data);
 }
 
 static void mrecv_ack_md5(mdata *data, struct sockaddr_in *addr)
 {
   mhost *t;
   mfile *m;
 
   mrecv_ack_search(&t, &m, data, addr);
   if(!t || !m){
     return;
   }
   mtimeget(&m->lastrecv);
   if(t->state != data->head.nstate){
     if(data->head.nstate == MAKUO_RECVSTATE_MD5OK){
       cprintf(1, m->comm, "%s: OK %s\r\n", t->hostname, m->fn);
8f9aeac1
       lprintf(1,          "%s: OK %s\n", __func__, m->fn);
634a23d7
     }
     if(data->head.nstate == MAKUO_RECVSTATE_MD5NG){
       cprintf(0, m->comm, "%s: NG %s\r\n", t->hostname, m->fn);
8f9aeac1
       lprintf(0,          "%s: NG %s\n", __func__, m->fn);
634a23d7
     }
   }
   t->state = data->head.nstate;
   mrecv_ack_report(m, t, data);
 }
 
 static void mrecv_ack(mdata *data, struct sockaddr_in *addr)
 {
   switch(data->head.opcode){
     case MAKUO_OP_PING:
       mrecv_ack_ping(data, addr);
       break;
8f9aeac1
     case MAKUO_OP_SEND:
634a23d7
       mrecv_ack_file(data, addr);
       break;
     case MAKUO_OP_MD5:
       mrecv_ack_md5(data, addr);
       break;
8f9aeac1
 
     /* 機能追加はここへ */
634a23d7
   }
 }
 
 /******************************************************************
 *
8f9aeac1
 * Request receive functions (for destination node tasks)
634a23d7
 *
 *******************************************************************/
 static void mrecv_req_ping(mdata *data, struct sockaddr_in *addr)
86badd32
 {
   mping *p;
   mfile *m;
634a23d7
   char buff[MAKUO_HOSTNAME_MAX + 1];
86badd32
   member_add(&addr->sin_addr, data);
   m = mfadd(0);
   if(!m){
8f9aeac1
     lprintf(0,"%s: out of memory\n", __func__);
86badd32
     return;
   }
634a23d7
   m->mdata.head.opcode = MAKUO_OP_PING;
   m->mdata.head.flags |= MAKUO_FLAG_ACK;
   m->mdata.head.reqid  = data->head.reqid;
   m->mdata.head.seqno  = 0;
   m->mdata.head.szdata = 0;
86badd32
   memcpy(&(m->addr), addr, sizeof(m->addr));
   if(gethostname(buff, sizeof(buff)) == -1){
     buff[0] = 0;
   }
   p = (mping *)(m->mdata.data);
   p->hostnamelen = strlen(buff);
   p->versionlen  = strlen(MAKUOSAN_VERSION);
   m->mdata.head.szdata = sizeof(mping) + p->hostnamelen + p->versionlen;
   m->mdata.p = p->data;
   memcpy(m->mdata.p, buff, p->hostnamelen);
   m->mdata.p += p->hostnamelen;
   memcpy(m->mdata.p, MAKUOSAN_VERSION, p->versionlen);
   m->mdata.p += p->versionlen;
   p->hostnamelen = htons(p->hostnamelen);
   p->versionlen  = htons(p->versionlen);
 }
 
634a23d7
 static void mrecv_req_exit(mdata *data, struct sockaddr_in *addr)
86badd32
 {
8f9aeac1
   mhost *t;
   for(t=members;t;t=t->next)
     if(!memcmp(&(t->ad), &(addr->sin_addr), sizeof(t->ad)))
86badd32
       break;
8f9aeac1
   member_del(t);
86badd32
 }
 
91adf830
 static void mrecv_req_file_data(mfile *m,  mdata *r)
86badd32
 {
   if(m->mdata.head.nstate != MAKUO_RECVSTATE_OPEN)
91adf830
     return;
86badd32
 
   if(m->lickflag){
     if(!seq_delmark(m, r->head.seqno)){
91adf830
       return;
86badd32
     }
   }else{
     if(r->head.seqno < m->mdata.head.seqno){
       seq_delmark(m, r->head.seqno);
     }else{
       m->mdata.head.seqno++;
       if(m->mdata.head.seqno < r->head.seqno){
         seq_addmark(m, m->mdata.head.seqno, r->head.seqno);
         m->mdata.head.seqno = r->head.seqno;
       }
     }
   }
   if(lseek(m->fd, (r->head.seqno - 1) * MAKUO_BUFFER_SIZE, SEEK_SET) == -1){
8f9aeac1
     lprintf(0, "%s: seek error seq=%d size=%d fd=%d err=%d\n", __func__, (int)r->head.seqno, r->head.szdata, m->fd, errno);
86badd32
     m->mdata.head.nstate = MAKUO_RECVSTATE_WRITEERROR;
   }else{
     if(write(m->fd, r->data, r->head.szdata) != -1){
       m->recvcount++;
     }else{
8f9aeac1
       lprintf(0, "%s: write error seqno=%d size=%d fd=%d err=%d\n", __func__, (int)r->head.seqno, r->head.szdata, m->fd, errno);
86badd32
       m->mdata.head.nstate = MAKUO_RECVSTATE_WRITEERROR;
     }
   }
 }
 
91adf830
 static void mrecv_req_file_break(mfile *m, mdata *r)
86badd32
 {
   mrecv_mfdel(m);
 }
 
91adf830
 static void mrecv_req_file_open(mfile *m, mdata *r)
86badd32
 {
   char fpath[PATH_MAX];
   char tpath[PATH_MAX];
 
   if(m->mdata.head.nstate != MAKUO_RECVSTATE_UPDATE)
91adf830
     return;
86badd32
 
   sprintf(fpath, "%s/%s", moption.base_dir, m->fn);
   sprintf(tpath, "%s/%s", moption.base_dir, m->tn);
 
   mfile *a = mfins(0);
634a23d7
   a->mdata.head.flags |= MAKUO_FLAG_ACK;
   a->mdata.head.opcode = r->head.opcode;
   a->mdata.head.reqid  = r->head.reqid;
   a->mdata.head.seqno  = r->head.seqno;
86badd32
   a->mdata.head.ostate = m->mdata.head.nstate;
   a->mdata.head.nstate = MAKUO_RECVSTATE_OPEN;
   m->mdata.head.nstate = MAKUO_RECVSTATE_OPEN;
   memcpy(&(a->addr), &(m->addr), sizeof(a->addr));
   if(S_ISLNK(m->fs.st_mode)){
     mtempname(moption.base_dir, m->fn, m->tn);
     sprintf(tpath, "%s/%s", moption.base_dir, m->tn);
     if(symlink(m->ln, m->tn) != -1){
8f9aeac1
       lprintf(2, "%s: open %s -> %s\n", __func__, m->ln, m->fn);
86badd32
     }else{
8f9aeac1
       lprintf(0, "%s: symlink error %s\n", __func__, m->fn);
86badd32
       m->mdata.head.nstate = MAKUO_RECVSTATE_OPENERROR;
       a->mdata.head.nstate = m->mdata.head.nstate;
     }
   }else{
     if(S_ISDIR(m->fs.st_mode)){
       if(!is_dir(fpath)){
         mcreatedir(moption.base_dir, m->fn, m->fs.st_mode & 0xFFF);
         mkdir(fpath, m->fs.st_mode & 0xFFF);
       }else{
         chmod(fpath, m->fs.st_mode & 0xFFF);
       }
       if(!is_dir(fpath)){
8f9aeac1
         lprintf(0,"%s: mkdir error %s\n", __func__, m->fn);
86badd32
         m->mdata.head.nstate = MAKUO_RECVSTATE_OPENERROR;
         a->mdata.head.nstate = m->mdata.head.nstate;
       }
     }
     if(S_ISREG(m->fs.st_mode)){
       mtempname(moption.base_dir, m->fn, m->tn);
       sprintf(tpath, "%s/%s", moption.base_dir, m->tn);
       m->fd = mcreate(moption.base_dir, m->tn, m->fs.st_mode);
       if(m->fd == -1){
8f9aeac1
         lprintf(0, "%s: open error %s\n", __func__, m->fn);
86badd32
         m->mdata.head.nstate = MAKUO_RECVSTATE_OPENERROR;
         a->mdata.head.nstate = m->mdata.head.nstate;
       }
     }
   }
 }
 
91adf830
 static void mrecv_req_file_last(mfile *m, mdata *r)
 {
   mrecv_mfdel(m);
 }
 
 static void mrecv_req_file_close(mfile *m, mdata *r)
86badd32
 {
   struct utimbuf mftime;
   char  fpath[PATH_MAX];
   char  tpath[PATH_MAX];
   sprintf(fpath, "%s/%s", moption.base_dir, m->fn);
   sprintf(tpath, "%s/%s", moption.base_dir, m->tn);
 
91adf830
   switch(m->mdata.head.nstate){
     case MAKUO_RECVSTATE_OPEN:
     case MAKUO_RECVSTATE_UPDATE:
     case MAKUO_RECVSTATE_CLOSE:
     case MAKUO_RECVSTATE_CLOSEERROR:
       break;
     default:
       return;
   }
 
   mfile *a = mfins(0);
   a->mdata.head.flags |= MAKUO_FLAG_ACK;
   a->mdata.head.opcode = r->head.opcode;
   a->mdata.head.reqid  = r->head.reqid;
   a->mdata.head.seqno  = r->head.seqno;
   a->mdata.head.ostate = m->mdata.head.nstate;
   a->mdata.head.nstate = MAKUO_RECVSTATE_CLOSE;
   memcpy(&(a->addr), &(m->addr), sizeof(a->addr));
 
   switch(m->mdata.head.nstate){
     case MAKUO_RECVSTATE_OPEN:
       break;
     case MAKUO_RECVSTATE_UPDATE:
     case MAKUO_RECVSTATE_CLOSE:
       return;
     case MAKUO_RECVSTATE_CLOSEERROR:
       a->mdata.head.nstate = MAKUO_RECVSTATE_CLOSEERROR;
       return;
   }
 
   if(m->fd != -1){
     fstat(m->fd, &(a->fs));
     close(m->fd);
   }
   m->fd = -1;
   mftime.actime  = m->fs.st_ctime; 
   mftime.modtime = m->fs.st_mtime;
   if(S_ISLNK(m->fs.st_mode)){
     if(!mrename(moption.base_dir, m->tn, m->fn)){
       lprintf(2, "%s: close %s -> %s\n", __func__, m->ln, m->fn);
     }else{
       a->mdata.head.nstate = MAKUO_RECVSTATE_CLOSEERROR;
       mremove(moption.base_dir, m->tn);
       lprintf(0, "%s: close error %s -> %s\n", __func__, m->ln, m->fn);
     }
     return;
   }
   if(S_ISDIR(m->fs.st_mode)){
     utime(fpath, &mftime);
   }else{
     utime(tpath, &mftime);
     if(a->fs.st_size != m->fs.st_size){
       a->mdata.head.nstate = MAKUO_RECVSTATE_CLOSEERROR;
       mremove(moption.base_dir, m->tn);
       lprintf(0, "%s: close error %s (file size mismatch %d != %d)\n", __func__, m->fn, (int)(a->fs.st_size), (int)(m->fs.st_size));
       lprintf(0, "%s: seq=%d max=%d markcnt=%d\n", __func__, m->mdata.head.seqno, m->seqnomax, m->markcount);
     }else{
       if(!mrename(moption.base_dir, m->tn, m->fn)){
         lprintf(2, "%s: close %s recv=%d mark=%d\n", __func__, m->fn , m->recvcount, m->markcount);
86badd32
       }else{
91adf830
         a->mdata.head.nstate = MAKUO_RECVSTATE_CLOSEERROR;
         mremove(moption.base_dir, m->tn);
         lprintf(0, "%s: close error %s\n", __func__, m->fn);
86badd32
       }
     }
   }
91adf830
   if(!geteuid()){
     chown(fpath, m->fs.st_uid, m->fs.st_gid);
   }
86badd32
 }
 
91adf830
 static void mrecv_req_file_mark(mfile *m, mdata *r)
86badd32
 {
   if(m->mdata.head.nstate != MAKUO_RECVSTATE_OPEN)
91adf830
     return;
86badd32
 
   mfile *a = mfins(0);
634a23d7
   a->mdata.head.flags |= MAKUO_FLAG_ACK;
   a->mdata.head.opcode = r->head.opcode;
   a->mdata.head.reqid  = r->head.reqid;
   a->mdata.head.seqno  = r->head.seqno;
86badd32
   a->mdata.head.nstate = m->mdata.head.nstate;
634a23d7
   a->mdata.head.szdata = 0;
86badd32
   memcpy(&(a->addr), &(m->addr), sizeof(a->addr));
   m->lickflag = 1;
   a->lickflag = 1;
   if(m->mdata.head.seqno < m->seqnomax){
     seq_addmark(m, m->mdata.head.seqno, m->seqnomax + 1);
     m->mdata.head.seqno = m->seqnomax;
   }
   if(m->markcount){
     if(MAKUO_BUFFER_SIZE < m->markcount * sizeof(uint32_t)){
       a->marksize = MAKUO_BUFFER_SIZE / sizeof(uint32_t);
     }else{
       a->marksize = m->markcount;
     }
     a->markcount = a->marksize;
     a->mark = malloc(a->marksize * sizeof(uint32_t));
     memcpy(a->mark, m->mark, a->marksize * sizeof(uint32_t));
8f9aeac1
     lprintf(3, "%s: retry %s recv=%d mark=%d reqest=%d\n", __func__, m->fn , m->recvcount, m->markcount, a->markcount);
86badd32
   }
 }
 
91adf830
 static void mrecv_req_file_stat(mfile *m, mdata *r)
86badd32
 {
91adf830
   mstat fs;
   mfile *a;
   struct utimbuf mftime;
 
   a = mfins(0);
   a->mdata.head.flags |= MAKUO_FLAG_ACK;
   a->mdata.head.opcode = m->mdata.head.opcode;
   a->mdata.head.reqid  = m->mdata.head.reqid;
   a->mdata.head.szdata = 0;
   a->mdata.head.seqno  = m->mdata.head.seqno;
   memcpy(&(a->addr), &(m->addr), sizeof(a->addr));
   if(moption.dontrecv){
     m->mdata.head.nstate = MAKUO_RECVSTATE_READONLY;
   }else{
     if(S_ISLNK(m->fs.st_mode)){
       m->mdata.head.nstate = linkcmp(m);
     }else{
       if(lstat(m->fn, &(a->fs)) == -1){
         m->mdata.head.nstate = MAKUO_RECVSTATE_UPDATE;
       }else{
         m->mdata.head.nstate = statcmp(&(m->fs), &(a->fs));
       }
     }
86badd32
   }
91adf830
   a->mdata.head.nstate = m->mdata.head.nstate;
 }
 
 static void mrecv_req_file_next(mfile *m,  mdata *r)
 {
86badd32
   switch(r->head.nstate){
91adf830
     case MAKUO_SENDSTATE_STAT:
       lprintf(9,"%s: MAKUO_SENDSTATE_STAT: state=%d %s\n", __func__,  m->mdata.head.nstate, m->fn);
       mrecv_req_file_stat(m, r);
       break;
 
86badd32
     case MAKUO_SENDSTATE_OPEN:
8f9aeac1
       lprintf(9,"%s: MAKUO_SENDSTATE_OPEN : state=%d %s\n", __func__,  m->mdata.head.nstate, m->fn);
91adf830
       mrecv_req_file_open(m, r);
       break;
 
     case MAKUO_SENDSTATE_DATA:
       mrecv_req_file_data(m, r);
       break;
 
86badd32
     case MAKUO_SENDSTATE_MARK:
8f9aeac1
       lprintf(9,"%s: MAKUO_SENDSTATE_MARK : state=%d seqno=%d max=%d cnt=%d %s\n", __func__,
86badd32
              m->mdata.head.nstate, m->mdata.head.seqno, m->seqnomax, m->markcount, m->fn);
91adf830
       mrecv_req_file_mark(m, r);
       break;
 
86badd32
     case MAKUO_SENDSTATE_CLOSE:
8f9aeac1
       lprintf(9,"%s: MAKUO_SENDSTATE_CLOSE: state=%d %s\n", __func__,  m->mdata.head.nstate, m->fn);
91adf830
       mrecv_req_file_close(m, r);
       break;
 
     case MAKUO_SENDSTATE_LAST:
       lprintf(9,"%s: MAKUO_SENDSTATE_LAST : state=%d %s\n", __func__,  m->mdata.head.nstate, m->fn);
       mrecv_req_file_last(m, r);
       break;
 
     case MAKUO_SENDSTATE_BREAK:
       lprintf(9,"%s: MAKUO_SENDSTATE_BREAK: state=%d %s\n", __func__,  m->mdata.head.nstate, m->fn);
       mrecv_req_file_break(m, r);
       break;
86badd32
   }
 }
 
91adf830
 
 static void mrecv_req_send(mdata *data, struct sockaddr_in *addr)
86badd32
 {
   mstat fs;
91adf830
   mfile *m; 
   uint16_t fnlen;
   uint16_t lnlen;
86badd32
 
91adf830
   for(m=mftop[1];m;m=m->next){
     if(!memcmp(&m->addr, addr, sizeof(m->addr)) && m->mdata.head.reqid == data->head.reqid){
       break;
     }
   }
86badd32
 
91adf830
   if(!m){
     /* create object */
86badd32
     m = mfadd(1);
91adf830
     if(!m){
       lprintf(0, "%s: out of memory\n", __func__);
       return;
     }
 
     /* copy header */
86badd32
     memcpy(&(m->addr), addr, sizeof(m->addr));
     memcpy(&(m->mdata.head), &(data->head), sizeof(m->mdata.head));
91adf830
     data->p = data->data;
86badd32
 
     /* read mstat */
     memcpy(&fs, data->p, sizeof(fs));
     data->p += sizeof(fs);
 
     /* stat = mstat */
     m->fs.st_mode  = ntohl(fs.mode);
     m->fs.st_uid   = ntohs(fs.uid);
     m->fs.st_gid   = ntohs(fs.gid);
     m->fs.st_size  = ((off_t)ntohl(fs.sizeh) << 32) + (off_t)ntohl(fs.sizel);
     m->fs.st_mtime = ntohl(fs.mtime);
     m->fs.st_ctime = ntohl(fs.ctime);
     fnlen = ntohs(fs.fnlen);
     lnlen = ntohs(fs.lnlen);
 
     /* read filename */
     memcpy(m->fn, data->p, fnlen);
     m->fn[fnlen] = 0;
     data->p += fnlen;
 
     /* read linkname */
     memcpy(m->ln, data->p, lnlen);    
     m->ln[lnlen] = 0;
     data->p += lnlen;
 
91adf830
     /* Number of blocks */
86badd32
     m->seqnomax = m->fs.st_size / MAKUO_BUFFER_SIZE;
     if(m->fs.st_size % MAKUO_BUFFER_SIZE){
       m->seqnomax++; 
     }
   }
91adf830
   mtimeget(&(m->lastrecv));
   mrecv_req_file_next(m, data);
86badd32
 }
 
634a23d7
 static void mrecv_req_md5_open(mfile *m, mdata *data, struct sockaddr_in *addr)
86badd32
 {
   int    r;
   int    l;
   mfile *a;
   mhash *h;
 
   if(!m){
     m = mfadd(1);
     memcpy(&(m->addr), addr, sizeof(m->addr));
     memcpy(&(m->mdata.head), &(data->head), sizeof(m->mdata.head));
     h = (mhash *)(data->data);
     l = ntohs(h->fnlen);
     memcpy(m->fn, h->filename, l);
     m->fn[l] = 0;
     m->fd = open(m->fn, O_RDONLY);
     if(m->fd == -1){
       m->mdata.head.nstate = MAKUO_RECVSTATE_OPENERROR;
     }else{
       r = md5sum(m->fd, m->mdata.data);
       close(m->fd);
       m->fd = -1;
       if(r == -1){
8f9aeac1
 	      lprintf(0, "%s: file read error %s\n", __func__, m->fn);
86badd32
         m->mdata.head.nstate = MAKUO_RECVSTATE_READERROR;
       }else{
         if(!memcmp(m->mdata.data, data->data, 16)){
           m->mdata.head.nstate = MAKUO_RECVSTATE_MD5OK;
         }else{
           m->mdata.head.nstate = MAKUO_RECVSTATE_MD5NG;
         }
       }
     }
   }
   a=mfadd(0);
634a23d7
   a->mdata.head.flags |= MAKUO_FLAG_ACK;
   a->mdata.head.opcode = m->mdata.head.opcode;
   a->mdata.head.reqid  = m->mdata.head.reqid;
   a->mdata.head.seqno  = 0;
   a->mdata.head.szdata = 0;
86badd32
   a->mdata.head.nstate = m->mdata.head.nstate;
   memcpy(&(a->addr), addr, sizeof(a->addr));
   mtimeget(&(m->lastrecv));
 }
 
634a23d7
 static void mrecv_req_md5_close(mfile *m, mdata *data, struct sockaddr_in *addr)
86badd32
 {
   mfile *a = mfadd(0);
634a23d7
   a->mdata.head.flags |= MAKUO_FLAG_ACK;
   a->mdata.head.opcode = data->head.opcode;
   a->mdata.head.reqid  = data->head.reqid;
   a->mdata.head.szdata = 0;
   a->mdata.head.seqno  = 0;
86badd32
   a->mdata.head.nstate = MAKUO_RECVSTATE_CLOSE;
   memcpy(&(a->addr), addr, sizeof(a->addr));
   mrecv_mfdel(m);
 }
 
 /*
3434d319
  * md5チェック要求を受け取ったときの処理
  * mfileオブジェクトを生成して
  * 対象ファイルのmd5を取得する
86badd32
  */
634a23d7
 static void mrecv_req_md5(mdata *data, struct sockaddr_in *addr)
86badd32
 {
   mfile *m = mftop[1];
   while(m){
     if(!memcmp(&m->addr, addr, sizeof(m->addr)) && m->mdata.head.reqid == data->head.reqid){
       mtimeget(&m->lastrecv);
       break;
     }
     m = m->next;
   }
   switch(data->head.nstate){
     case MAKUO_SENDSTATE_OPEN:
634a23d7
       mrecv_req_md5_open(m, data, addr);
86badd32
       break;
     case MAKUO_SENDSTATE_CLOSE:
634a23d7
       mrecv_req_md5_close(m, data, addr);
86badd32
       break;
   }
 }
 
634a23d7
 static void mrecv_req(mdata *data, struct sockaddr_in *addr)
86badd32
 {
634a23d7
   switch(data->head.opcode){
86badd32
     case MAKUO_OP_PING:
634a23d7
       mrecv_req_ping(data, addr);
86badd32
       break;
     case MAKUO_OP_EXIT:
634a23d7
       mrecv_req_exit(data, addr);
86badd32
       break;
8f9aeac1
     case MAKUO_OP_SEND:
91adf830
       mrecv_req_send(data, addr);
86badd32
       break;
     case MAKUO_OP_MD5:
634a23d7
       mrecv_req_md5(data, addr);
86badd32
       break;
8f9aeac1
 
     /* 機能追加はここへ */
86badd32
   }
 }