-#include "config.h"
-
-int send_meta(conn_list_t *cl, const char *buffer, int length)
-{
- char outbuf[MAXBUFSIZE];
- char *bufp;
-cp
- if(debug_lvl >= DEBUG_META)
- syslog(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s): %s"), int length,
- cl->name, cl->hostname, buffer);
-
- if(cl->status.encryptout)
- {
- if(EVP_EncryptUpdate(cl->cipher_outctx, cl->buffer + cl->buflen, NULL, inbuf, length) != 1)
- {
- syslog(LOG_ERR, _("Error during encryption of outgoing metadata to %s (%s)"), cl->name, cl->hostname);
- return -1;
- }
- bufp = outbuf;
- }
- else
- bufp = buffer;
-
- if(write(cl->meta_socket, bufp, length) < 0)
- {
- syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %m"), cl->name, cl->hostname);
- return -1;
- }
-cp
- return 0;
+#include "system.h"
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#include "avl_tree.h"
+#include "connection.h"
+#include "logger.h"
+#include "meta.h"
+#include "net.h"
+#include "protocol.h"
+#include "utils.h"
+#include "xalloc.h"
+
+bool send_meta(connection_t *c, const char *buffer, int length) {
+ int outlen;
+ int result;
+
+ if(!c) {
+ logger(LOG_ERR, "send_meta() called with NULL pointer!");
+ abort();
+ }
+
+ ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
+ c->name, c->hostname);
+
+ if(!c->outbuflen)
+ c->last_flushed_time = now;
+
+ /* Find room in connection's buffer */
+ if(length + c->outbuflen > c->outbufsize) {
+ c->outbufsize = length + c->outbuflen;
+ c->outbuf = xrealloc(c->outbuf, c->outbufsize);
+ }
+
+ if(length + c->outbuflen + c->outbufstart > c->outbufsize) {
+ memmove(c->outbuf, c->outbuf + c->outbufstart, c->outbuflen);
+ c->outbufstart = 0;
+ }
+
+ /* Add our data to buffer */
+ if(c->status.encryptout) {
+ result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen,
+ &outlen, (unsigned char *)buffer, length);
+ if(!result || outlen < length) {
+ logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s",
+ c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
+ return false;
+ } else if(outlen > length) {
+ logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!");
+ abort();
+ }
+ c->outbuflen += outlen;
+ } else {
+ memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length);
+ c->outbuflen += length;
+ }
+
+ return true;
+}
+
+bool flush_meta(connection_t *c) {
+ int result;
+
+ ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)",
+ c->outbuflen, c->name, c->hostname);
+
+ while(c->outbuflen) {
+ result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0);
+ if(result <= 0) {
+ if(!errno || errno == EPIPE) {
+ ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
+ c->name, c->hostname);
+ } else if(errno == EINTR) {
+ continue;
+ } else if(sockwouldblock(sockerrno)) {
+ ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block",
+ c->outbuflen, c->name, c->hostname);
+ return true;
+ } else {
+ logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name,
+ c->hostname, sockstrerror(sockerrno));
+ }
+
+ return false;
+ }
+
+ c->outbufstart += result;
+ c->outbuflen -= result;
+ }
+
+ c->outbufstart = 0; /* avoid unnecessary memmoves */
+ return true;