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; }
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; }
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; }
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); }
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; }
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); }
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; }
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); }
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; }
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); }
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; }
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); }
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; }