int SendTransaction(int sd, char *buffer, int len, char status) { char work[CF_BUFSIZE]; int wlen; memset(work, 0, sizeof(work)); if (len == 0) { wlen = strlen(buffer); } else { wlen = len; } if (wlen > CF_BUFSIZE - CF_INBAND_OFFSET) { Log(LOG_LEVEL_ERR, "SendTransaction: wlen (%d) > %d - %d", wlen, CF_BUFSIZE, CF_INBAND_OFFSET); ProgrammingError("SendTransaction software failure"); } snprintf(work, CF_INBAND_OFFSET, "%c %d", status, wlen); memcpy(work + CF_INBAND_OFFSET, buffer, wlen); if (SendSocketStream(sd, work, wlen + CF_INBAND_OFFSET, 0) == -1) { return -1; } return 0; }
int SendTransaction(int sd, char *buffer, int len, char status) { char work[CF_BUFSIZE]; int wlen; memset(work, 0, sizeof(work)); if (len == 0) { wlen = strlen(buffer); } else { wlen = len; } if (wlen > CF_BUFSIZE - CF_INBAND_OFFSET) { CfOut(cf_error, "", "SendTransaction: wlen (%d) > %d - %d", wlen, CF_BUFSIZE, CF_INBAND_OFFSET); FatalError("SendTransaction software failure"); } snprintf(work, CF_INBAND_OFFSET, "%c %d", status, wlen); memcpy(work + CF_INBAND_OFFSET, buffer, wlen); CfDebug("Transaction Send[%s][Packed text]\n", work); if (SendSocketStream(sd, work, wlen + CF_INBAND_OFFSET, 0) == -1) { return -1; } return 0; }
/** * @param len is the number of bytes to send, or 0 if buffer is a * '\0'-terminated string so strlen(buffer) can used. */ int SendTransaction(const ConnectionInfo *conn_info, const char *buffer, int len, char status) { assert(status == CF_MORE || status == CF_DONE); char work[CF_BUFSIZE] = { 0 }; int ret; if (len == 0) { len = strlen(buffer); } if (len > CF_BUFSIZE - CF_INBAND_OFFSET) { Log(LOG_LEVEL_ERR, "SendTransaction: len (%d) > %d - %d", len, CF_BUFSIZE, CF_INBAND_OFFSET); return -1; } snprintf(work, CF_INBAND_OFFSET, "%c %d", status, len); memcpy(work + CF_INBAND_OFFSET, buffer, len); Log(LOG_LEVEL_DEBUG, "SendTransaction header: %s", work); LogRaw(LOG_LEVEL_DEBUG, "SendTransaction data: ", work + CF_INBAND_OFFSET, len); switch(ConnectionInfoProtocolVersion(conn_info)) { case CF_PROTOCOL_CLASSIC: ret = SendSocketStream(ConnectionInfoSocket(conn_info), work, len + CF_INBAND_OFFSET); break; case CF_PROTOCOL_TLS: ret = TLSSend(ConnectionInfoSSL(conn_info), work, len + CF_INBAND_OFFSET); break; default: UnexpectedError("SendTransaction: ProtocolVersion %d!", ConnectionInfoProtocolVersion(conn_info)); ret = -1; } if (ret == -1) return -1; else return 0; }
void CfGetFile(ServerFileGetState *args) { int fd; off_t n_read, total = 0, sendlen = 0, count = 0; char sendbuffer[CF_BUFSIZE + 256], filename[CF_BUFSIZE]; struct stat sb; int blocksize = 2048; ConnectionInfo *conn_info = &(args->connect)->conn_info; TranslatePath(filename, args->replyfile); stat(filename, &sb); Log(LOG_LEVEL_DEBUG, "CfGetFile('%s'), size = %" PRIdMAX, filename, (intmax_t) sb.st_size); /* Now check to see if we have remote permission */ if (!TransferRights(filename, args, &sb)) { RefuseAccess(args->connect, args->buf_size, ""); snprintf(sendbuffer, CF_BUFSIZE, "%s", CF_FAILEDSTR); if (conn_info->type == CF_PROTOCOL_CLASSIC) { SendSocketStream(conn_info->sd, sendbuffer, args->buf_size); } else if (conn_info->type == CF_PROTOCOL_TLS) { TLSSend(conn_info->ssl, sendbuffer, args->buf_size); } return; } /* File transfer */ if ((fd = open(filename, O_RDONLY)) == -1) { Log(LOG_LEVEL_ERR, "Open error of file '%s'. (open: %s)", filename, GetErrorStr()); snprintf(sendbuffer, CF_BUFSIZE, "%s", CF_FAILEDSTR); if (conn_info->type == CF_PROTOCOL_CLASSIC) { SendSocketStream(conn_info->sd, sendbuffer, args->buf_size); } else if (conn_info->type == CF_PROTOCOL_TLS) { TLSSend(conn_info->ssl, sendbuffer, args->buf_size); } } else { int div = 3; if (sb.st_size > 10485760L) /* File larger than 10 MB, checks every 64kB */ { div = 32; } while (true) { memset(sendbuffer, 0, CF_BUFSIZE); Log(LOG_LEVEL_DEBUG, "Now reading from disk..."); if ((n_read = read(fd, sendbuffer, blocksize)) == -1) { Log(LOG_LEVEL_ERR, "Read failed in GetFile. (read: %s)", GetErrorStr()); break; } if (n_read == 0) { break; } else { off_t savedlen = sb.st_size; /* check the file is not changing at source */ if (count++ % div == 0) /* Don't do this too often */ { if (stat(filename, &sb)) { Log(LOG_LEVEL_ERR, "Cannot stat file '%s'. (stat: %s)", filename, GetErrorStr()); break; } } if (sb.st_size != savedlen) { snprintf(sendbuffer, CF_BUFSIZE, "%s%s: %s", CF_CHANGEDSTR1, CF_CHANGEDSTR2, filename); if (conn_info->type == CF_PROTOCOL_CLASSIC) { if (SendSocketStream(conn_info->sd, sendbuffer, blocksize) == -1) { Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr()); } } else if (conn_info->type == CF_PROTOCOL_TLS) { if (TLSSend(conn_info->ssl, sendbuffer, blocksize) == -1) { Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr()); } } Log(LOG_LEVEL_DEBUG, "Aborting transfer after %" PRIdMAX ": file is changing rapidly at source.", (intmax_t)total); break; } if ((savedlen - total) / blocksize > 0) { sendlen = blocksize; } else if (savedlen != 0) { sendlen = (savedlen - total); } } total += n_read; if (conn_info->type == CF_PROTOCOL_CLASSIC) { if (SendSocketStream(conn_info->sd, sendbuffer, sendlen) == -1) { Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr()); break; } } else if (conn_info->type == CF_PROTOCOL_TLS) { if (TLSSend(conn_info->ssl, sendbuffer, sendlen) == -1) { Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr()); break; } } } close(fd); } }
/** * @param len is the number of bytes to send, or 0 if buffer is a * '\0'-terminated string so strlen(buffer) can used. * @return -1 in case of error or connection closed * (also currently returns 0 for success but don't count on it) * @NOTE #buffer can't be of zero length, our protocol * does not allow empty transactions! The reason is that * ReceiveTransaction() can't differentiate between that * and connection closed. * @NOTE (len <= CF_BUFSIZE - CF_INBAND_OFFSET) */ int SendTransaction(const ConnectionInfo *conn_info, const char *buffer, int len, char status) { assert(status == CF_MORE || status == CF_DONE); char work[CF_BUFSIZE] = { 0 }; int ret; if (len == 0) { len = strlen(buffer); } /* Not allowed to send zero-payload packets, because (ReceiveTransaction() == 0) currently means connection closed. */ assert(len > 0); if (len > CF_BUFSIZE - CF_INBAND_OFFSET) { Log(LOG_LEVEL_ERR, "SendTransaction: len (%d) > %d - %d", len, CF_BUFSIZE, CF_INBAND_OFFSET); return -1; } snprintf(work, CF_INBAND_OFFSET, "%c %d", status, len); memcpy(work + CF_INBAND_OFFSET, buffer, len); Log(LOG_LEVEL_DEBUG, "SendTransaction header: %s", work); LogRaw(LOG_LEVEL_DEBUG, "SendTransaction data: ", work + CF_INBAND_OFFSET, len); switch(conn_info->protocol) { case CF_PROTOCOL_CLASSIC: ret = SendSocketStream(conn_info->sd, work, len + CF_INBAND_OFFSET); break; case CF_PROTOCOL_TLS: ret = TLSSend(conn_info->ssl, work, len + CF_INBAND_OFFSET); if (ret <= 0) { ret = -1; } break; default: UnexpectedError("SendTransaction: ProtocolVersion %d!", conn_info->protocol); ret = -1; } if (ret == -1) { return -1; /* error */ } else { /* SSL_MODE_AUTO_RETRY guarantees no partial writes. */ assert(ret == len + CF_INBAND_OFFSET); return 0; } }