X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit-ng%2Fctdlclient.c;h=54041afbcc8534ed5a54a28ddf8e15aedb10001c;hb=91bc31f50a6d93ad0c01d24e29e61a3f5b972cba;hp=decb31adba036ada8d0554d3d8626e0cba544289;hpb=351c06b478ca3292be86472f76becbd68df8c1f9;p=citadel.git diff --git a/webcit-ng/ctdlclient.c b/webcit-ng/ctdlclient.c index decb31adb..54041afbc 100644 --- a/webcit-ng/ctdlclient.c +++ b/webcit-ng/ctdlclient.c @@ -1,16 +1,17 @@ -/* - * Functions that handle communication with a Citadel Server - * - * Copyright (c) 1987-2018 by the citadel.org team - * - * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// +// Functions that handle communication with a Citadel Server +// +// Copyright (c) 1987-2018 by the citadel.org team +// +// This program is open source software. It runs great on the +// Linux operating system (and probably elsewhere). You can use, +// copy, and run it under the terms of the GNU General Public +// License version 3. Richard Stallman is an asshole communist. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "webcit.h" @@ -18,9 +19,29 @@ struct ctdlsession *cpool = NULL; // linked list of connections to the Citade pthread_mutex_t cpool_mutex = PTHREAD_MUTEX_INITIALIZER; // Lock it before modifying +/* + * Read a specific number of bytes of binary data from the Citadel server. + * Returns the number of bytes read or -1 for error. + */ +int ctdl_read_binary(struct ctdlsession *ctdl, char *buf, int bytes_requested) +{ + int bytes_read = 0; + int c = 0; + + while (bytes_read < bytes_requested) { + c = read(ctdl->sock, &buf[bytes_read], bytes_requested-bytes_read); + if (c <= 0) { + syslog(LOG_DEBUG, "Socket error or zero-length read"); + return (-1); + } + bytes_read += c; + } + return (bytes_read); +} + + /* * Read a newline-terminated line of text from the Citadel server. - * Implemented in terms of client_read() and is therefore transparent... * Returns the string length or -1 for error. */ int ctdl_readline(struct ctdlsession *ctdl, char *buf, int maxbytes) @@ -28,26 +49,27 @@ int ctdl_readline(struct ctdlsession *ctdl, char *buf, int maxbytes) int len = 0; int c = 0; - if (buf == NULL) return(-1); + if (buf == NULL) + return (-1); while (len < maxbytes) { c = read(ctdl->sock, &buf[len], 1); if (c <= 0) { syslog(LOG_DEBUG, "Socket error or zero-length read"); - return(-1); + return (-1); } if (buf[len] == '\n') { - if ( (len >0) && (buf[len-1] == '\r') ) { + if ((len > 0) && (buf[len - 1] == '\r')) { --len; } buf[len] = 0; // syslog(LOG_DEBUG, "\033[33m[ %s\033[0m", buf); - return(len); + return (len); } ++len; } // syslog(LOG_DEBUG, "\033[33m[ %s\033[0m", buf); - return(len); + return (len); } @@ -56,7 +78,7 @@ int ctdl_readline(struct ctdlsession *ctdl, char *buf, int maxbytes) * Implemented in terms of ctdl_readline() and is therefore transparent... * Returns a newly allocated StrBuf or NULL for error. */ -StrBuf *ctdl_readtextmsg(struct ctdlsession *ctdl) +StrBuf *ctdl_readtextmsg(struct ctdlsession * ctdl) { char buf[1024]; StrBuf *sj = NewStrBuf(); @@ -64,7 +86,7 @@ StrBuf *ctdl_readtextmsg(struct ctdlsession *ctdl) return NULL; } - while ( (ctdl_readline(ctdl, buf, sizeof(buf)) >= 0) && (strcmp(buf, "000")) ) { + while ((ctdl_readline(ctdl, buf, sizeof(buf)) >= 0) && (strcmp(buf, "000"))) { StrBufAppendPrintf(sj, "%s\n", buf); } @@ -76,7 +98,8 @@ StrBuf *ctdl_readtextmsg(struct ctdlsession *ctdl) * Write to the Citadel server. For now we're just wrapping write() in case we * need to add anything else later. */ -ssize_t ctdl_write(struct ctdlsession *ctdl, const void *buf, size_t count) { +ssize_t ctdl_write(struct ctdlsession * ctdl, const void *buf, size_t count) +{ return write(ctdl->sock, buf, count); } @@ -84,7 +107,7 @@ ssize_t ctdl_write(struct ctdlsession *ctdl, const void *buf, size_t count) { /* * printf() type function to send data to the Citadel Server. */ -void ctdl_printf(struct ctdlsession *ctdl, const char *format,...) +void ctdl_printf(struct ctdlsession *ctdl, const char *format, ...) { va_list arg_ptr; StrBuf *Buf = NewStrBuf(); @@ -94,7 +117,7 @@ void ctdl_printf(struct ctdlsession *ctdl, const char *format,...) va_end(arg_ptr); syslog(LOG_DEBUG, "\033[32m] %s\033[0m", ChrPtr(Buf)); - ctdl_write(ctdl, (char *)ChrPtr(Buf), StrLength(Buf)); + ctdl_write(ctdl, (char *) ChrPtr(Buf), StrLength(Buf)); ctdl_write(ctdl, "\n", 1); FreeStrBuf(&Buf); } @@ -115,13 +138,13 @@ int uds_connectsock(char *sockpath) s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { syslog(LOG_WARNING, "Can't create socket [%s]: %s", sockpath, strerror(errno)); - return(-1); + return (-1); } if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { syslog(LOG_WARNING, "Can't connect [%s]: %s", sockpath, strerror(errno)); close(s); - return(-1); + return (-1); } return s; } @@ -155,12 +178,12 @@ int tcp_connectsock(char *host, char *service) * Handle numeric IPv4 and IPv6 addresses */ rc = inet_pton(AF_INET, host, &serveraddr); - if (rc == 1) { /* dotted quad */ + if (rc == 1) { /* dotted quad */ hints.ai_family = AF_INET; hints.ai_flags |= AI_NUMERICHOST; } else { rc = inet_pton(AF_INET6, host, &serveraddr); - if (rc == 1) { /* IPv6 address */ + if (rc == 1) { /* IPv6 address */ hints.ai_family = AF_INET6; hints.ai_flags |= AI_NUMERICHOST; } @@ -172,7 +195,7 @@ int tcp_connectsock(char *host, char *service) if (rc != 0) { syslog(LOG_DEBUG, "%s: %s", host, gai_strerror(rc)); freeaddrinfo(res); - return(-1); + return (-1); } /* @@ -180,15 +203,18 @@ int tcp_connectsock(char *host, char *service) */ for (ai = res; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family == AF_INET) syslog(LOG_DEBUG, "Trying IPv4"); - else if (ai->ai_family == AF_INET6) syslog(LOG_DEBUG, "Trying IPv6"); - else syslog(LOG_WARNING, "This is going to fail."); + if (ai->ai_family == AF_INET) + syslog(LOG_DEBUG, "Trying IPv4"); + else if (ai->ai_family == AF_INET6) + syslog(LOG_DEBUG, "Trying IPv6"); + else + syslog(LOG_WARNING, "This is going to fail."); s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (s < 0) { syslog(LOG_WARNING, "socket() failed: %s", strerror(errno)); freeaddrinfo(res); - return(-1); + return (-1); } rc = connect(s, ai->ai_addr, ai->ai_addrlen); if (rc >= 0) { @@ -197,32 +223,25 @@ int tcp_connectsock(char *host, char *service) fdflags = fcntl(rc, F_GETFL); if (fdflags < 0) { - syslog(LOG_ERR, - "unable to get socket %d flags! %s", - rc, - strerror(errno)); + syslog(LOG_ERR, "unable to get socket %d flags! %s", rc, strerror(errno)); close(rc); return -1; } fdflags = fdflags | O_NONBLOCK; if (fcntl(rc, F_SETFL, fdflags) < 0) { - syslog(LOG_ERR, - "unable to set socket %d nonblocking flags! %s", - rc, - strerror(errno)); + syslog(LOG_ERR, "unable to set socket %d nonblocking flags! %s", rc, strerror(errno)); close(s); return -1; } - return(s); - } - else { + return (s); + } else { syslog(LOG_WARNING, "connect() failed: %s", strerror(errno)); close(s); } } - freeaddrinfo(res); - return(-1); + freeaddrinfo(res); + return (-1); } @@ -232,14 +251,15 @@ int tcp_connectsock(char *host, char *service) */ void extract_auth(struct http_transaction *h, char *authbuf, int authbuflen) { - if (authbuf == NULL) return; + if (authbuf == NULL) + return; authbuf[0] = 0; char *authheader = header_val(h, "Authorization"); if (authheader) { if (!strncasecmp(authheader, "Basic ", 6)) { safestrncpy(authbuf, &authheader[6], authbuflen); - return; // HTTP-AUTH was found -- stop here + return; // HTTP-AUTH was found -- stop here } } @@ -255,10 +275,9 @@ void extract_auth(struct http_transaction *h, char *authbuf, int authbuflen) if (strlen(authbuf) < 3) { // impossibly small authbuf[0] = 0; } - return; // Cookie auth was found -- stop here + return; // Cookie auth was found -- stop here } } - // no authorization found in headers ... this is an anonymous session } @@ -281,21 +300,20 @@ int login_to_citadel(struct ctdlsession *c, char *auth, char *resultbuf) if (resultbuf != NULL) { buf = resultbuf; - } - else { + } else { buf = localbuf; } buflen = CtdlDecodeBase64(buf, auth, strlen(auth)); extract_token(supplied_username, buf, 0, ':', sizeof supplied_username); extract_token(supplied_password, buf, 1, ':', sizeof supplied_password); - syslog(LOG_DEBUG, "Supplied credentials: username=%s, pwlen=%d", supplied_username, (int)strlen(supplied_password)); + syslog(LOG_DEBUG, "Supplied credentials: username=%s, pwlen=%d", supplied_username, (int) strlen(supplied_password)); ctdl_printf(c, "USER %s", supplied_username); ctdl_readline(c, buf, 1024); if (buf[0] != '3') { syslog(LOG_DEBUG, "No such user: %s", buf); - return(1); // no such user; resultbuf will explain why + return (1); // no such user; resultbuf will explain why } ctdl_printf(c, "PASS %s", supplied_password); @@ -305,18 +323,19 @@ int login_to_citadel(struct ctdlsession *c, char *auth, char *resultbuf) strcpy(c->auth, auth); extract_token(c->whoami, &buf[4], 0, '|', sizeof c->whoami); syslog(LOG_DEBUG, "Login succeeded: %s", buf); - return(0); + return (0); } syslog(LOG_DEBUG, "Login failed: %s", buf); - return(1); // login failed; resultbuf will explain why + return (1); // login failed; resultbuf will explain why } /* * Hunt for, or create, a connection to our Citadel Server */ -struct ctdlsession *connect_to_citadel(struct http_transaction *h) { +struct ctdlsession *connect_to_citadel(struct http_transaction *h) +{ struct ctdlsession *cptr = NULL; struct ctdlsession *my_session = NULL; int is_new_session = 0; @@ -326,16 +345,17 @@ struct ctdlsession *connect_to_citadel(struct http_transaction *h) { // Does the request carry a username and password? extract_auth(h, auth, sizeof auth); - syslog(LOG_DEBUG, "Session auth: %s", auth); // remove this log when development is done + syslog(LOG_DEBUG, "Session auth: %s", auth); // remove this log when development is done // Lock the connection pool while we claim our connection pthread_mutex_lock(&cpool_mutex); - if (cpool != NULL) for (cptr = cpool; ((cptr != NULL) && (my_session == NULL)); cptr = cptr->next) { - if ( (cptr->is_bound == 0) && (!strcmp(cptr->auth, auth)) ) { - my_session = cptr; - my_session->is_bound = 1; + if (cpool != NULL) + for (cptr = cpool; ((cptr != NULL) && (my_session == NULL)); cptr = cptr->next) { + if ((cptr->is_bound == 0) && (!strcmp(cptr->auth, auth))) { + my_session = cptr; + my_session->is_bound = 1; + } } - } if (my_session == NULL) { syslog(LOG_DEBUG, "No qualifying sessions , starting a new one"); my_session = malloc(sizeof(struct ctdlsession)); @@ -349,13 +369,12 @@ struct ctdlsession *connect_to_citadel(struct http_transaction *h) { } pthread_mutex_unlock(&cpool_mutex); if (my_session == NULL) { - return(NULL); // oh well + return (NULL); // oh well } if (my_session->sock < 3) { is_new_session = 1; - } - else { // make sure our Citadel session is still good + } else { // make sure our Citadel session is still good int test_conn; test_conn = ctdl_write(my_session, HKEY("NOOP\n")); if (test_conn < 5) { @@ -363,8 +382,7 @@ struct ctdlsession *connect_to_citadel(struct http_transaction *h) { close(my_session->sock); my_session->sock = 0; is_new_session = 1; - } - else { + } else { test_conn = ctdl_readline(my_session, buf, sizeof(buf)); if (test_conn < 1) { syslog(LOG_DEBUG, "Citadel session is broken , must reconnect"); @@ -389,14 +407,15 @@ struct ctdlsession *connect_to_citadel(struct http_transaction *h) { my_session->last_access = time(NULL); ++my_session->num_requests_handled; - return(my_session); + return (my_session); } /* * Release our Citadel Server connection back into the pool. */ -void disconnect_from_citadel(struct ctdlsession *ctdl) { +void disconnect_from_citadel(struct ctdlsession *ctdl) +{ pthread_mutex_lock(&cpool_mutex); ctdl->is_bound = 0; pthread_mutex_unlock(&cpool_mutex);