+ syslog(9, ">>>%s", buf);
+#endif
+ return rc;
+}
+
+
+/*
+ * Read binary data from server into memory using a series of server READ commands.
+ * returns the read content as StrBuf
+ */
+int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf)
+{
+ wcsession *WCC = WC;
+ size_t bytes_read = 0;
+ size_t this_block = 0;
+ int rc;
+
+ if (Ret == NULL) {
+ return -1;
+ }
+
+ while (bytes_read < total_len) {
+
+ if (WCC->serv_sock==-1) {
+ FlushStrBuf(Ret);
+ return -1;
+ }
+
+ serv_printf("READ "SIZE_T_FMT"|"SIZE_T_FMT, bytes_read, total_len-bytes_read);
+ if ( (rc = StrBuf_ServGetln(Buf) > 0) && (GetServerStatus(Buf, NULL) == 6) )
+ {
+ if (rc < 0)
+ return rc;
+ StrBufCutLeft(Buf, 4);
+ this_block = StrTol(Buf);
+ rc = StrBuf_ServGetBLOBBuffered(Ret, this_block);
+ if (rc < 0) {
+ syslog(1, "Server connection broken during download\n");
+ wc_backtrace();
+ if (WCC->serv_sock > 0) close(WCC->serv_sock);
+ WCC->serv_sock = (-1);
+ WCC->connected = 0;
+ WCC->logged_in = 0;
+ return rc;
+ }
+ bytes_read += rc;
+ }
+ }
+
+ return StrLength(Ret);
+}
+
+
+int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target)
+{
+ const char *Error;
+#ifdef HAVE_OPENSSL
+ const char *pch, *pchs;
+ int rlen, len, retval = 0;
+
+ if (is_https) {
+ int ntries = 0;
+ if (StrLength(Hdr->ReadBuf) > 0)
+ {
+ pchs = ChrPtr(Hdr->ReadBuf);
+ pch = strchr(pchs, '\n');
+ if (pch != NULL) {
+ rlen = 0;
+ len = pch - pchs;
+ if (len > 0 && (*(pch - 1) == '\r') )
+ rlen ++;
+ StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
+ StrBufCutLeft(Hdr->ReadBuf, len + 1);
+ return len - rlen;
+ }
+ }
+
+ while (retval == 0) {
+ pch = NULL;
+ pchs = ChrPtr(Hdr->ReadBuf);
+ if (*pchs != '\0')
+ pch = strchr(pchs, '\n');
+ if (pch == NULL) {
+ retval = client_read_sslbuffer(Hdr->ReadBuf, SLEEPING);
+ pchs = ChrPtr(Hdr->ReadBuf);
+ pch = strchr(pchs, '\n');
+ if (pch == NULL)
+ retval = 0;
+ }
+ if (retval == 0) {
+ sleeeeeeeeeep(1);
+ ntries ++;
+ }
+ if (ntries > 10)
+ return 0;
+ }
+ if ((retval > 0) && (pch != NULL)) {
+ rlen = 0;
+ len = pch - pchs;
+ if (len > 0 && (*(pch - 1) == '\r') )
+ rlen ++;
+ StrBufSub(Target, Hdr->ReadBuf, 0, len - rlen);
+ StrBufCutLeft(Hdr->ReadBuf, len + 1);
+ return len - rlen;
+
+ }
+ else
+ return -1;
+ }
+ else
+#endif
+ return StrBufTCP_read_buffered_line_fast(Target,
+ Hdr->ReadBuf,
+ &Hdr->Pos,
+ &Hdr->http_sock,
+ 5,
+ 1,
+ &Error);
+}
+
+
+/*
+ * This is a generic function to set up a master socket for listening on
+ * a TCP port. The server shuts down if the bind fails. (IPv4/IPv6 version)
+ *
+ * ip_addr IP address to bind
+ * port_number port number to bind
+ * queue_len number of incoming connections to allow in the queue
+ */
+int webcit_tcp_server(char *ip_addr, int port_number, int queue_len)
+{
+ struct protoent *p;
+ struct sockaddr_in6 sin6;
+ struct sockaddr_in sin4;
+ int s, i, b;
+ int ip_version = 6;
+
+ memset(&sin6, 0, sizeof(sin6));
+ memset(&sin4, 0, sizeof(sin4));
+ sin6.sin6_family = AF_INET6;
+ sin4.sin_family = AF_INET;
+
+ if ( (ip_addr == NULL) /* any IPv6 */
+ || (IsEmptyStr(ip_addr))
+ || (!strcmp(ip_addr, "*"))
+ ) {
+ ip_version = 6;
+ sin6.sin6_addr = in6addr_any;
+ }
+ else if (!strcmp(ip_addr, "0.0.0.0")) /* any IPv4 */
+ {
+ ip_version = 4;
+ sin4.sin_addr.s_addr = INADDR_ANY;
+ }
+ else if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':'))) /* specific IPv4 */
+ {
+ ip_version = 4;
+ if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) {
+ syslog(1, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
+ return (-WC_EXIT_BIND);
+ }
+ }
+ else /* specific IPv6 */
+ {
+ ip_version = 6;
+ if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) {
+ syslog(1, "Error binding to [%s] : %s\n", ip_addr, strerror(errno));
+ return (-WC_EXIT_BIND);
+ }
+ }
+
+ if (port_number == 0) {
+ syslog(1, "Cannot start: no port number specified.\n");
+ return (-WC_EXIT_BIND);
+ }
+ sin6.sin6_port = htons((u_short) port_number);
+ sin4.sin_port = htons((u_short) port_number);
+
+ p = getprotobyname("tcp");
+
+ s = socket( ((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto));
+ if (s < 0) {
+ syslog(1, "Can't create a listening socket: %s\n", strerror(errno));
+ return (-WC_EXIT_BIND);
+ }
+ /* Set some socket options that make sense. */
+ i = 1;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+
+ if (ip_version == 6) {
+ b = bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
+ }
+ else {
+ b = bind(s, (struct sockaddr *) &sin4, sizeof(sin4));
+ }
+
+ if (b < 0) {
+ syslog(1, "Can't bind: %s\n", strerror(errno));
+ close(s);
+ return (-WC_EXIT_BIND);
+ }
+
+ if (listen(s, queue_len) < 0) {
+ syslog(1, "Can't listen: %s\n", strerror(errno));
+ close(s);
+ return (-WC_EXIT_BIND);
+ }
+ return (s);
+}
+
+
+/*
+ * Create a Unix domain socket and listen on it
+ * sockpath - file name of the unix domain socket
+ * queue_len - Number of incoming connections to allow in the queue
+ */
+int webcit_uds_server(char *sockpath, int queue_len)
+{
+ struct sockaddr_un addr;
+ int s;
+ int i;
+ int actual_queue_len;
+
+ actual_queue_len = queue_len;
+ if (actual_queue_len < 5) actual_queue_len = 5;
+
+ i = unlink(sockpath);
+ if ((i != 0) && (errno != ENOENT)) {
+ syslog(1, "webcit: can't unlink %s: %s\n",
+ sockpath, strerror(errno));
+ return (-WC_EXIT_BIND);
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s < 0) {
+ syslog(1, "webcit: Can't create a unix domain socket: %s\n", strerror(errno));
+ return (-WC_EXIT_BIND);
+ }
+
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ syslog(1, "webcit: Can't bind: %s\n", strerror(errno));
+ close(s);
+ return (-WC_EXIT_BIND);
+ }
+
+ if (listen(s, actual_queue_len) < 0) {
+ syslog(1, "webcit: Can't listen: %s\n", strerror(errno));
+ close(s);
+ return (-WC_EXIT_BIND);
+ }
+
+ chmod(sockpath, 0777);
+ return(s);
+}
+
+
+
+
+/*
+ * Read data from the client socket.
+ *
+ * sock socket fd to read from
+ * buf buffer to read into
+ * bytes number of bytes to read
+ * timeout Number of seconds to wait before timing out
+ *
+ * Possible return values:
+ * 1 Requested number of bytes has been read.
+ * 0 Request timed out.
+ * -1 Connection is broken, or other error.
+ */
+int client_read_to(ParsedHttpHdrs *Hdr, StrBuf *Target, int bytes, int timeout)
+{
+ const char *Error;
+ int retval = 0;
+
+#ifdef HAVE_OPENSSL
+ if (is_https) {
+ long bufremain = 0;
+ long baselen;
+
+ baselen = StrLength(Target);
+
+ if (Hdr->Pos == NULL)
+ Hdr->Pos = ChrPtr(Hdr->ReadBuf);
+
+ if (StrLength(Hdr->ReadBuf) > 0)
+ {
+ bufremain = StrLength(Hdr->ReadBuf) - (Hdr->Pos - ChrPtr(Hdr->ReadBuf));
+
+ if (bytes < bufremain)
+ bufremain = bytes;
+ StrBufAppendBufPlain(Target, Hdr->Pos, bufremain, 0);
+ StrBufCutLeft(Hdr->ReadBuf, bufremain);
+ }
+
+ if (bytes > bufremain)
+ {
+ while ((StrLength(Hdr->ReadBuf) + StrLength(Target) < bytes + baselen) &&
+ (retval >= 0))
+ retval = client_read_sslbuffer(Hdr->ReadBuf, timeout);
+ if (retval >= 0) {
+ StrBufAppendBuf(Target, Hdr->ReadBuf, 0); /* todo: Buf > bytes? */
+ return 1;
+ }
+ else {
+ syslog(2, "client_read_ssl() failed\n");
+ return -1;
+ }
+ }
+ else
+ return 1;
+ }