Exemple #1
0
int csync_recv_file(FILE *out)
{
	char buffer[512];
	int rc, chunk;
	long size;

	if ( !conn_gets(buffer, 100) || sscanf(buffer, "octet-stream %ld\n", &size) != 1 ) {
		if (!strcmp(buffer, "ERROR\n")) { errno=EIO; return -1; }
		csync_fatal("Format-error while receiving data.\n");
	}

	csync_debug(3, "Receiving %ld bytes ..\n", size);

	while ( size > 0 ) {
		chunk = size > 512 ? 512 : size;
		rc = conn_read(buffer, chunk);

		if ( rc <= 0 )
			csync_fatal("Read-error while receiving data.\n");
		chunk = rc;

		rc = fwrite(buffer, chunk, 1, out);
		if ( rc != 1 )
			csync_fatal("Write-error while receiving data.\n");

		size -= chunk;
		csync_debug(3, "Got %d bytes, %ld bytes left ..\n",
				chunk, size);
	}

	fflush(out);
	rewind(out);
	return 0;
}
Exemple #2
0
static int do_read_size(client_ctx *cx)
{
	conn *incoming;	
	uint8_t *data;
	size_t size;
	
	incoming = &cx->incoming;

	if (incoming->result < 0) {
		pr_err("read error: %s", uv_strerror(incoming->result));
		return do_kill(cx);
	}

	data = (uint8_t *)incoming->buf;
	size = (size_t)incoming->offset;

	if (size >= 2) {
		incoming->req_size = ntohs(*((uint16_t *)data));
		if (incoming->req_size > sizeof(incoming->buf)-2) {
			pr_err("read error: %d req size", incoming->req_size);
			return do_kill(cx);
		}
		return do_read_request(cx);
	}
	else {		
		conn_read(incoming);
	}

	return s_read_size;
}
Exemple #3
0
int bot_work(struct bot* b)
{
		char buf[4096];
		conn_read(b->conn, buf);
		char* tmp = buf;
		char* msg = buf;
		while(1)
		{
			while(*tmp!='\n')
			{
				++tmp;
				if(!(*tmp)) break;
			}
			if(*tmp)
			{
				*tmp=0;
				bot_parsemsg(b, msg);
				msg=++tmp;
			}
			else
			{
				bot_parsemsg(b, msg);
				break;
			}
		}
		if(globalkill) return 1;
		return 0;
}
Exemple #4
0
void proxy_connect_handler(conn_t *c, void *data) {
    DBGTRACE();
    proxy_t *p = c->data;
    proxy_send_request(p);
    c->read_close_handler = proxy_read_close_handler;
    c->write_handler = NULL;
    conn_read(c, proxy_read_handler);
}
Exemple #5
0
void *worker_run(void* userdata) {
  int num_events, flush_outbox;
  worker_t* self = userdata;
  ev_event_t *event;
  conn_t *conn;

  ev_init(&self->loop);
  ev_watch(&self->loop, self->conn_queue[0], EV_READABLE, self);
  ev_watch(&self->loop, self->msg_queue[0], EV_READABLE, NULL);

  while(self->running) {
    num_events = ev_poll(&self->loop);
    flush_outbox = 0;

    if (num_events == -1)
      continue;

    while (--num_events >= 0) {
      event = self->loop.fired[num_events];

      if (!event->fired)
        continue;

      if (!event->userdata) {
        if (event->fired & EV_READABLE)
          worker_flush_inbox(self);
        else
          flush_outbox = 1;

        continue;

      } else if (event->userdata == self) {
        worker_accept(self);
        continue;
      }

      conn = event->userdata;

      if (event->fired & EV_READABLE)
        if (conn_read(conn) == -1)
          continue;

      if (event->fired & EV_WRITEABLE)
        if (conn_write(conn) == -1)
          continue;

    }

    if (flush_outbox)
      worker_flush_outbox(self);
  }

  worker_cleanup(self);
  return NULL;
}
Exemple #6
0
static bool echo_read(conn_t *conn, struct buf *buf)
{
	buf->used = BUFFER_SIZE;
	if (!conn_read(conn, buf->bytes, &buf->used)) {
		free(buf);
		return false;
	}

	printf("%*s\n", buf->used, buf->bytes);
	return conn_next(conn, echo_write, buf);
}
Exemple #7
0
static int do_write_response(client_ctx *cx)
{
	conn *c = &cx->incoming;

	conn_write(c, c->resp_buf, c->resp_size);

	buff_pull(&cx->incoming);
	c->req_size = 0;
	c->resp_size = 0;

	conn_read(c);

	return s_read_size;
}
Exemple #8
0
void client_finish_init(server_ctx *sx, client_ctx *cx)
{
	conn *incoming;

	cx->sx = sx;
	cx->state = s_read_size;

	incoming = &cx->incoming;	
	incoming->client = cx;
	incoming->result = 0;
	incoming->offset = 0;
	incoming->req_size = 0;

	/* Wait for the initial packet. */
	conn_read(incoming);
}
Exemple #9
0
static int do_read_request(client_ctx *cx)
{
	conn *incoming;
	size_t size;

	incoming = &cx->incoming;

	if (incoming->result < 0) {
		pr_err("read error: %s", uv_strerror(incoming->result));
		return do_kill(cx);
	}

	size = (size_t)incoming->offset;

	if (size >= (size_t)incoming->req_size + 2) {		
		return do_process_request(cx);
	}
	else {		
		conn_read(incoming);
	}

	return s_read_request;
}
Exemple #10
0
inline void worker_accept(worker_t* self) {
  conn_t *conn;
  int sock;

  ev_watch(&self->loop, self->conn_queue[0], EV_READABLE, self);

  if (read(self->conn_queue[0], &sock, sizeof(sock)) != sizeof(sock)) {
    if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
      printf("error reading from conn_queue\n");

    return;
  }

  if (sock == -1) {
    self->running = 0;
    return;
  }

  conn = conn_init(4096);
  conn->sock = sock;
  conn->worker = self;
  conn_set_nonblock(conn);
  conn_read(conn);
}
Exemple #11
0
enum conn_cbresult_t tcp_standard_callback(tcpconn_t *connection, enum conn_callback_t id, void *userdata)
{
	int res = CONN_CBRESULT_OK;
	int n, advancestep;
	size_t used;
	time_t start, expire;
	int keysize;
	char *certsubject, *issuer, *fulltext;
	myconn_t *rec = (myconn_t *)userdata;

	dbgprintf("CB: %s\n", conn_callback_names[id]);

	switch (id) {
	  case CONN_CB_CONNECT_START:          /* Client mode: New outbound connection start */
		break;

	  case CONN_CB_CONNECT_FAILED:         /* Client mode: New outbound connection failed */
		rec->talkresult = TALK_CONN_FAILED;
		rec->textlog = newstrbuffer(0);
		addtobuffer(rec->textlog, strerror(connection->errcode));
		conn_close_connection(connection, NULL);
		break;

	  case CONN_CB_CONNECT_COMPLETE:       /* Client mode: New outbound connection succeded */
		rec->textlog = newstrbuffer(0);
		rec->talkresult = TALK_OK;		/* Will change below if we fail later */
		rec->readbufsz = USERBUFSZ;
		rec->readbuf = rec->readp = malloc(rec->readbufsz);
		*(rec->readbuf) = '\0';
		rec->writebuf = rec->writep = malloc(USERBUFSZ);
		*(rec->writebuf) = '\0';
		break;

	  case CONN_CB_SSLHANDSHAKE_OK:        /* Client/server mode: SSL handshake completed OK (peer certificate ready) */
		certsubject = conn_peer_certificate(connection, &start, &expire, &keysize, &issuer, &fulltext);
		if (certsubject) {
			rec->peercertificate = certsubject;	/* certsubject is malloc'ed by conn_peer_certificate */
			rec->peercertificateissuer = issuer;	/* ditto issuer */
			rec->peercertificatestart = start;
			rec->peercertificateexpiry = expire;
			rec->peercertificatekeysize = keysize;
			rec->peercertificatedetails = fulltext;
		}
		if (strcasecmp(rec->dialog[rec->step], "CLOSE") == 0) conn_close_connection(connection, NULL);
		break;

	  case CONN_CB_SSLHANDSHAKE_FAILED:    /* Client/server mode: SSL handshake failed (connection will close) */
		rec->talkresult = TALK_BADSSLHANDSHAKE;
		conn_close_connection(connection, NULL);
		break;

	  case CONN_CB_READCHECK:              /* Client/server mode: Check if application wants to read data */
		if (!rec->dialog[rec->step])
			res = CONN_CBRESULT_FAILED;
		else if (rec->istelnet > 0)
			res = CONN_CBRESULT_OK;
		else
			res = ((strncasecmp(rec->dialog[rec->step], "EXPECT:", 7) == 0) || (strncasecmp(rec->dialog[rec->step], "READ", 4) == 0)) ? CONN_CBRESULT_OK : CONN_CBRESULT_FAILED;
		break;

	  case CONN_CB_READ:                   /* Client/server mode: Ready for application to read data w/ conn_read() */
		/* Make sure we have some buffer space */
		used = (rec->readp - rec->readbuf);
		if ((rec->readbufsz - used) < USERBUFSZ) {
			rec->readbufsz += USERBUFSZ;
			rec->readbuf = (char *)realloc(rec->readbuf, rec->readbufsz);
			rec->readp = rec->readbuf + used;
		}
		/* Read the data */
		n = conn_read(connection, rec->readp, (rec->readbufsz - used - 1));
		if (n <= 0) return CONN_CBRESULT_OK;	/* n == 0 happens during SSL handshakes, n < 0 means connection will close */
		rec->bytesread += n;

		/* Process data for some protocols */
		if (rec->istelnet) n = telnet_datahandler(rec, n);
		if (rec->talkprotocol == TALK_PROTO_HTTP) n = http_datahandler(rec, n, 0, &advancestep);

		/* Save the data */
		if (n > 0) {
			*(rec->readp + n) = '\0';
			if (rec->talkprotocol == TALK_PROTO_PLAIN) addtobuffer(rec->textlog, rec->readp);
			rec->readp += n;
		}

		/* See how the dialog is progressing */
		if (strncasecmp(rec->dialog[rec->step], "EXPECT:", 7) == 0) {
			int explen, expstart;

			expstart = 7 + strspn(rec->dialog[rec->step] + 7, " \t");
			explen = strlen(rec->dialog[rec->step] + expstart);

			if ((n < explen) && (strncasecmp(rec->readbuf, rec->dialog[rec->step] + expstart, n) == 0)) {
				/* 
				 * Got the right data so far, but not the complete amount.
				 * Do nothing, we'll just keep reading until we have all of the data
				 */
			}
			else if (strncasecmp(rec->readbuf, rec->dialog[rec->step] + expstart, explen) == 0) {
				/* Got the expected data, go to next step */
				rec->step++;
				rec->readp = rec->readbuf;
				*rec->readp = '\0';
			}
			else {
				/* Got some unexpected data, give up */
				rec->talkresult = TALK_BADDATA;
				conn_close_connection(connection, NULL);
			}
		}
		else if (strcasecmp(rec->dialog[rec->step], "READALL") == 0) {
			/* No need to save the data twice (we store it in rec->textlog), so reset the readp to start of our readbuffer */
			rec->readp = rec->readbuf;
			*(rec->readp) = '\0';
			if (advancestep) rec->step++;
		}
		else if (strcasecmp(rec->dialog[rec->step], "READ") == 0) {
			rec->step++;
		}

		/* See if we have reached a point where we switch to TLS mode */
		if (rec->dialog[rec->step] && (strcasecmp(rec->dialog[rec->step], "STARTTLS") == 0)) {
			res = CONN_CBRESULT_STARTTLS;
			rec->step++;
		}

		/* See if we're done */
		if (strcasecmp(rec->dialog[rec->step], "CLOSE") == 0) conn_close_connection(connection, NULL);
		break;

	  case CONN_CB_WRITECHECK:             /* Client/server mode: Check if application wants to write data */
		if (!rec->dialog[rec->step])
			res = CONN_CBRESULT_FAILED;
		else if (rec->istelnet != 0)
			res = (rec->istelnet < 0) ? CONN_CBRESULT_OK : CONN_CBRESULT_FAILED;
		else {
			if ((*rec->writep == '\0') && (strncasecmp(rec->dialog[rec->step], "SEND:", 5) == 0)) {
				char *sendstart = rec->dialog[rec->step] + 5;
				sendstart += strspn(sendstart, " \t");
				strcpy(rec->writebuf, sendstart);
				rec->writep = rec->writebuf;
			}
			res = (*rec->writep != '\0') ? CONN_CBRESULT_OK : CONN_CBRESULT_FAILED;
		}
		break;

	  case CONN_CB_WRITE:                  /* Client/server mode: Ready for application to write data w/ conn_write() */
		if (rec->istelnet < 0) {
			n = conn_write(connection, rec->writep, -(rec->istelnet));
			if (n <= 0) return CONN_CBRESULT_OK;	/* n == 0 happens during SSL handshakes, n < 0 means connection will close */
			rec->writep += n;
			rec->istelnet += n; if (rec->istelnet == 0) rec->istelnet = 1;
		}
		else {
			n = conn_write(connection, rec->writep, strlen(rec->writep));
			if (n <= 0) return CONN_CBRESULT_OK;	/* n == 0 happens during SSL handshakes, n < 0 means connection will close */
			if (n > 0) {
				rec->byteswritten += n;
				switch (rec->talkprotocol) {
				  case TALK_PROTO_PLAIN:
				  case TALK_PROTO_HTTP:
					addtobufferraw(rec->textlog, rec->writep, n);
					break;
				  default:
					break;
				}
				rec->writep += n;
				if (*rec->writep == '\0') {
					rec->step++;	/* Next step */
					if (last_write_step(rec)) {
						conn_close_connection(connection, "w");
					}
				}
			}
		}

		/* See if we have reached a point where we switch to TLS mode */
		if (rec->dialog[rec->step] && (strcasecmp(rec->dialog[rec->step], "STARTTLS") == 0)) {
			res = CONN_CBRESULT_STARTTLS;
			rec->step++;
		}

		/* See if we're done */
		if (strcasecmp(rec->dialog[rec->step], "CLOSE") == 0) conn_close_connection(connection, NULL);
		break;

	  case CONN_CB_TIMEOUT:
		rec->talkresult = TALK_CONN_TIMEOUT;
		conn_close_connection(connection, NULL);
		break;

	  case CONN_CB_CLOSED:                 /* Client/server mode: Connection has been closed */
		/* See if we need to report an error from closing the connection unexpectedly */
		if ((rec->talkresult == TALK_OK) && rec->dialog[rec->step]) {
			/*
			 * We should only close if
			 * - we hit a CLOSE command
			 * - we hit the end of the command list (NULL dialog step)
			 * - peer disconnects during a READ step
			 * So if the current step is NOT a CLOSE or a READALL step, then 
			 * the close was unexpected - so flag it as an error.
			 */
			if ((strcasecmp(rec->dialog[rec->step], "CLOSE") != 0) && (strcasecmp(rec->dialog[rec->step], "READALL") != 0))
				rec->talkresult = TALK_INTERRUPTED;
		}
		rec->elapsedus = connection->elapsedus;
		return 0;

	  case CONN_CB_CLEANUP:                /* Client/server mode: Connection cleanup */
		if (rec->readbuf) xfree(rec->readbuf);
		if (rec->writebuf) xfree(rec->writebuf);
		connection->userdata = NULL;
		test_is_done(rec);
		return 0;

	  default:
		break;
	}

	return res;
}
/*
 * XXX multithread (socket read, file write)
 */
static int
recv_file()
{
	/* volatiles are for setjmp/longjmp */
	conn * volatile conn = NULL;
	char * volatile wbuf = NULL;
	volatile int fd = -1;
	volatile uint64_t remaining = maxsize;
	struct timeval st, et;
	int rv = 1;
	char *stat;

	if (timeout > 0) {
		struct itimerval it;

		if (sigsetjmp(toenv, 1)) {
			rv = 2;
			goto done;
		}
		it.it_value.tv_sec = timeout;
		it.it_value.tv_usec = 0;
		it.it_interval = it.it_value;

		signal(SIGALRM, send_timeout);
		setitimer(ITIMER_REAL, &it, NULL);
	}

	wbuf = malloc(bufsize);
	if (wbuf == NULL) {
		error("Could not allocate %d byte buffer, try using -b",
		      bufsize);
		goto done;
	}

	if (strcmp(path, "-") == 0)
		fd = STDOUT_FILENO;
	else
		fd = open(path, O_WRONLY|O_CREAT, 0644);
	if (fd < 0) {
		pwarning(path);
		goto done;
	}

	conn = conn_accept_tcp(sock, &clientip);
	if (conn == NULL) {
		error("Error accepting from %s", inet_ntoa(clientip));
		goto done;
	}
	log("%s: upload from %s started", path, inet_ntoa(clientip));

	gettimeofday(&st, NULL);
	while (maxsize == 0 || remaining > 0) {
		ssize_t cc, ncc;

		if (maxsize == 0 || remaining > bufsize)
			cc = bufsize;
		else
			cc = remaining;
		ncc = conn_read(conn, wbuf, cc);
		if (ncc < 0) {
			pwarning("socket read");
			goto done;
		}
		if (ncc == 0)
			break;

		cc = write(fd, wbuf, ncc);
		if (cc < 0) {
			pwarning("file write");
			goto done;
		}
		remaining -= cc;
		if (cc != ncc) {
			error("short write on file (%d != %d)", cc, ncc);
			goto done;
		}
	}
	/* Note that coming up short (remaining > 0) is not an error */
	rv = 0;

 done:
	gettimeofday(&et, NULL);

	if (timeout) {
		struct itimerval it;

		it.it_value.tv_sec = 0;
		it.it_value.tv_usec = 0;
		setitimer(ITIMER_REAL, &it, NULL);

	}
	if (conn != NULL)
		conn_close(conn);
	if (fd >= 0) {
		if (rv == 0 && fsync(fd) != 0) {
			perror(path);
			rv = 1;
		}
		close(fd);
	}
	if (wbuf != NULL)
		free(wbuf);

	timersub(&et, &st, &et);

	stat = rv == 0 ? "completed" : (rv == 1 ? "terminated" : "timed-out");
	if (maxsize && remaining)
		log("%s: upload %s after %llu (of max %llu) bytes "
		    "in %d.%03d seconds",
		    path, stat, maxsize-remaining, maxsize,
		    et.tv_sec, et.tv_usec/1000);
	else
		log("%s: upload %s after %llu bytes in %d.%03d seconds",
		    path, stat, maxsize-remaining,
		    et.tv_sec, et.tv_usec/1000);

	/* XXX unlink file on error? */
	return rv;
}
Exemple #13
0
static void proto_handle_get(conn_t* cn, const char* line) {
	struct stat st;

	// Reject filenames with just "." and ".."
	if(memcmp(line, ".\0", 2) == 0 || memcmp(line, "..\0", 3) == 0) {
		conn_printf(cn, "ERROR Protocol violation (%d)\n", __LINE__);
		conn_abort(cn);
		return;
	}

	if(lstat(line,&st) == 0) {
		if(S_ISREG(st.st_mode)) {
			int fd;
			md5_state_t md5_state;
			md5_init(&md5_state);
			char buffer[PATH_MAX];
			ssize_t size;
			char md5str[33];
			char modestr[11];

#ifdef O_NOATIME
			if((fd = open(line,O_RDONLY|O_NOATIME))==-1) {
#else
			if((fd = open(line,O_RDONLY))==-1) {
#endif

				conn_perror(cn, "WARNING open()");
				conn_printf(cn, "WARNING Can't open file: %s\n", line);
				return;
			}

			// Calcuate MD5
			{
				unsigned char md5bin[16];
				while((size = read(fd, buffer, sizeof buffer)))
					md5_append(&md5_state, (unsigned char*)buffer, size);
				md5_finish(&md5_state, (unsigned char*)md5bin);

				if(lseek(fd, SEEK_SET, 0)==-1) {
					conn_perror(cn, "ERROR lseek()");
					conn_abort(cn);
					return;
				}

				md5bin2str(md5bin, md5str);
			}

			mode2str(st.st_mode, modestr);
			conn_printf(cn, "PUT %ld %s %s %ld %ld %ld %s\n", 
				(long int)st.st_size,
				md5str,
				modestr,
				st.st_atime,
				st.st_ctime,
				st.st_mtime,
				line);
			while((size = read(fd, buffer, sizeof buffer))) 
				conn_write(cn, buffer, size);
			close(fd);
		}
		else if(S_ISDIR(st.st_mode)) {
			char modestr[11];
			mode2str(st.st_mode, modestr);
			conn_printf(cn, "MKDIR %s %ld %ld %ld %s\n",
				modestr,
				st.st_atime,
				st.st_ctime,
				st.st_mtime,
				line);
		}
		else if(S_ISLNK(st.st_mode)) {
			char buffer[PATH_MAX];
			conn_printf(cn, "SLNK %s\n", line);

			ssize_t l;
			if((l=readlink(line, buffer, sizeof buffer))==-1) {
				conn_perror(cn, "WARNING readlink()");
				return;
			}
			buffer[l] = '\0';
			conn_printf(cn, "%s\n", buffer);
		}
		else {
			conn_printf(cn, "WARNING Ignored %s\n", line);
		}
	}
}

static void proto_handle_put(conn_t* cn, const char* line) {
	const char* delim = " ";
	char* saveptr = NULL;
	char* token;
	char* ptr = (char*)line;
	int c = 0;

	ssize_t size = 0;
	mode_t mode = 0;
	time_t mtime = 0;
	time_t ctime = 0;
	time_t atime = 0;
	char* name = NULL;
	char* md5  = NULL;

	while((token = strtok_r(ptr, delim, &saveptr))) {
		switch(c) {
			case 0: size = atol(token); break;
			case 1: md5 = token; break;
			case 2: mode = str2mode(token); break;
			case 3: atime = atol(token); break; 
			case 4: ctime = atol(token); break;
			case 5: mtime = atol(token); break;
			case 6: name = token; break;
		}
		c++;
		ptr = NULL;
	}

	if(c != 7) {
		conn_printf(cn, "ERROR Protocol violation (%d)\n", __LINE__);
		conn_abort(cn);
		return ;
	}

	int fd = creat(name, O_CREAT|O_TRUNC);
	if(fd == -1) {
		conn_perror(cn, "WARNING creat()");
		return;
	}

	if(chmod(name,mode)==-1) {
		perror("WARNING chmod()");
	}

	struct utimbuf t;
	t.actime = atime;
	t.modtime = mtime;
	if(utime(name,&t)==-1) {
		perror("WARNING utime");
	}

	// CONTENT
	int bytes_left = size;
	int r;
	md5_state_t md5_state;
	unsigned char md5bin[16];
	char md5str[33];
	md5_init(&md5_state);
	while(!cn->abort && bytes_left) {
		if(cn->rbuf_len == 0) 
			(void)conn_read(cn);

		r = MIN(bytes_left, cn->rbuf_len);
		if(r) {
			write(fd, cn->rbuf, r);
			md5_append(&md5_state, (unsigned char*)cn->rbuf, r);
			conn_shift(cn,r);
			bytes_left -= r;
		}

		assert(bytes_left >= 0);
	}

	close(fd);
	md5_finish(&md5_state, (unsigned char*)md5bin);
	md5bin2str(md5bin, md5str);

	// Check md5
	if(strcmp(md5str,md5)!=0) {
		// Mismatch!
		conn_printf(cn, "WARNING %s md5-mismatch (%s <-> %s), removing file\n", 
			name,
			md5str, md5);
		if(unlink(name)==-1) {
			perror("WARNING: unlink()");
		}
	}
	else {
		struct utimbuf t;
		t.actime = atime;
		t.modtime = mtime;
		if(utime(name,&t)==-1) {
			perror("utime");
			conn_printf(cn, "WARNING Can't timestamp on directory: %s\n", name);
		}
		// md5 is fine
		conn_printf(cn, "GET %s\n", name);
	}
}

static void proto_handle_slnk(conn_t* cn, const char* line) {
	char curdir[PATH_MAX];

	// read next line to get target
	char target[PATH_MAX];
	if(!conn_readline(cn, target, sizeof target))
		return;

	getcwd(curdir, sizeof curdir);

	// Make sure it dosnt exist
	unlink(line);

	if(chdir(my_dirname(line))==-1) {
		conn_perror(cn, "WARNING chdir()");
		return;
	}

	if(symlink(target, my_basename(line))==-1) {
		conn_perror(cn, "ERROR symlink()");
		conn_abort(cn);
		return;
	}

	chdir(curdir);

	conn_printf(cn, "GET %s\n", line);
}
Exemple #14
0
int csync_rs_check(const char *filename, int isreg)
{
	FILE *basis_file = 0, *sig_file = 0;
	char buffer1[512], buffer2[512];
	int rc, chunk, found_diff = 0;
	int backup_errno;
	rs_stats_t stats;
	rs_result result;
	long size;
	char tmpfname[MAXPATHLEN];

	csync_debug(3, "Csync2 / Librsync: csync_rs_check('%s', %d [%s])\n",
		filename, isreg, isreg ? "regular file" : "non-regular file");

	csync_debug(3, "Opening basis_file and sig_file..\n");

	sig_file = open_temp_file(tmpfname, prefixsubst(filename));
	if ( !sig_file ) goto io_error;
	if (unlink(tmpfname) < 0) goto io_error;

	basis_file = fopen(prefixsubst(filename), "rb");
	if ( !basis_file ) {  /* ?? why a tmp file? */
		basis_file = open_temp_file(tmpfname, prefixsubst(filename));
		if ( !basis_file ) goto io_error;
		if (unlink(tmpfname) < 0) goto io_error;
	}

	if ( isreg ) {
		csync_debug(3, "Running rs_sig_file() from librsync....\n");
		result = rs_sig_file(basis_file, sig_file,
				RS_DEFAULT_BLOCK_LEN, RS_DEFAULT_STRONG_LEN, &stats);
		if (result != RS_DONE) {
			csync_debug(0, "Internal error from rsync library!\n");
			goto error;
		}
	}

	fclose(basis_file);
	basis_file = 0;

	{
		char line[100];
		csync_debug(3, "Reading signature size from peer....\n");
		if ( !conn_gets(line, 100) || sscanf(line, "octet-stream %ld\n", &size) != 1 )
			csync_fatal("Format-error while receiving data.\n");
	}

	fflush(sig_file);
	if ( size != ftell(sig_file) ) {
		csync_debug(2, "Signature size differs: local=%d, peer=%d\n",
				ftell(sig_file), size);
		found_diff = 1;
	}
	rewind(sig_file);

	csync_debug(3, "Receiving %ld bytes ..\n", size);

	while ( size > 0 ) {
		chunk = size > 512 ? 512 : size;
		rc = conn_read(buffer1, chunk);

		if ( rc <= 0 )
			csync_fatal("Read-error while receiving data.\n");
		chunk = rc;

		if ( fread(buffer2, chunk, 1, sig_file) != 1 ) {
			csync_debug(2, "Found EOF in local sig file.\n");
			found_diff = 1;
		}
		if ( memcmp(buffer1, buffer2, chunk) ) {
			csync_debug(2, "Found diff in sig at -%d:-%d\n",
					size, size-chunk);
			found_diff = 1;
		}

		size -= chunk;
		csync_debug(3, "Got %d bytes, %ld bytes left ..\n",
				chunk, size);
	}

	csync_debug(3, "File has been checked successfully (%s).\n",
		found_diff ? "difference found" : "files are equal");
	fclose(sig_file);
	return found_diff;

io_error:
	csync_debug(0, "I/O Error '%s' in rsync-check: %s\n",
			strerror(errno), prefixsubst(filename));

error:;
	backup_errno = errno;
	if ( basis_file ) fclose(basis_file);
	if ( sig_file )   fclose(sig_file);
	errno = backup_errno;
	return -1;
}