/* * This file is part of the Poliqarp suite. * * Copyright (C) 2004-2009 by Instytut Podstaw Informatyki Polskiej * Akademii Nauk (IPI PAN; Institute of Computer Science, Polish * Academy of Sciences; cf. www.ipipan.waw.pl). All rights reserved. * * This file may be distributed and/or modified under the terms of the * GNU General Public License version 2 as published by the Free Software * Foundation and appearing in the file gpl.txt included in the packaging * of this file. (See http://www.gnu.org/licenses/translations.html for * unofficial translations.) * * A commercial license is available from IPI PAN (contact * Michal.Ciesiolka@ipipan.waw.pl or ipi@ipipan.waw.pl for more * information). Licensees holding a valid commercial license from IPI * PAN may use this file in accordance with that license. * * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. */ #include <string.h> #include "sockstream.h" #include "sockets.h" #include "utils.h" #define BUF_SIZE 4096 #define OUTPUT_BUF_SIZE 32768 sockstream_t *sockstream_create(int fd) { sockstream_t *res = malloc(sizeof(sockstream_t)); res->fd = fd; res->buf = malloc(BUF_SIZE); res->start = res->used = 0; res->obuf = malloc(OUTPUT_BUF_SIZE); res->oused = 0; return res; } void sockstream_free(sockstream_t *s) { closesocket(s->fd); free(s->obuf); free(s->buf); free(s); } string_t sockstream_read_string(sockstream_t *s) { string_t res = string_create(); char *eol = memchr(s->buf + s->start, '\n', s->used); int goon = 1; if (eol != NULL) { size_t numbytes = eol - s->buf - s->start + 1; string_append_strn(res, s->buf + s->start, numbytes - 1); s->start += numbytes; s->used -= numbytes; return res; } string_append_strn(res, s->buf + s->start, s->used); while (goon) { size_t numbytes; ssize_t recvd; s->start = 0; recvd = recv(s->fd, s->buf, BUF_SIZE, 0); if (recvd < 0) { if (!peer_disconnected()) socket_error(_("recv() failed")); else recvd = 0; } s->used = recvd; if (s->used == 0) break; eol = memchr(s->buf, '\n', s->used); if (eol != NULL) { numbytes = eol - s->buf; goon = 0; } else { numbytes = s->used; } string_append_strn(res, s->buf, numbytes); s->start += (numbytes + 1); s->used -= (numbytes + 1); } return res; } static void socket_write_cstring_len(int fd, const char *str, size_t length) { while (length) { ssize_t written = send(fd, str, length, 0); if (written < 0) { if (!peer_disconnected()) socket_error(_("send() failed")); return; } str += written; length -= written; } } void socket_write_string(int sock, const string_t str) { socket_write_cstring_len(sock, string_str(str), string_len(str)); } void socket_write_cstring(int sock, const char *str) { socket_write_cstring_len(sock, str, strlen(str)); } void socket_writeln(int sock) { char newline = '\n'; int written = send(sock, &newline, 1, 0); if (written != 1 && !peer_disconnected()) socket_error(_("send() failed")); } void socket_writeln_string(int sock, const string_t str) { socket_write_string(sock, str); socket_writeln(sock); } void sockstream_output_flush(sockstream_t *s) { socket_write_cstring_len(s->fd, s->obuf, s->oused); s->oused = 0; } void sockstream_write_cstring(sockstream_t *s, const char *str) { size_t len = strlen(str), ofs = 0; while (ofs < len) { size_t towrite = MIN(OUTPUT_BUF_SIZE - s->oused, len - ofs); memcpy(s->obuf + s->oused, str + ofs, towrite); s->oused += towrite; ofs += towrite; if (s->oused == OUTPUT_BUF_SIZE) sockstream_output_flush(s); } }