con->ldap_dn = NULL;
}
+ FreeStrBuf(&con->MigrateBuf);
+ FreeStrBuf(&con->ReadBuf);
CtdlLogPrintf(CTDL_DEBUG, "Done with RemoveContext()\n");
}
* Generate a unique session number and insert this context into
* the list.
*/
+ me->MigrateBuf = NewStrBuf();
+ me->ReadBuf = NewStrBuf();
begin_critical_section(S_SESSION_TABLE);
me->cs_pid = ++next_pid;
me->prev = NULL;
struct CitContext *prev; /* Link to previous session in list */
struct CitContext *next; /* Link to next session in the list */
- int state; /* thread state (see CON_ values below) */
- int kill_me; /* Set to nonzero to flag for termination */
- int client_socket;
int cs_pid; /* session ID */
int dont_term; /* for special activities like artv so we don't get killed */
time_t lastcmd; /* time of last command executed */
time_t lastidle; /* For computing idle time */
+ int state; /* thread state (see CON_ values below) */
+ int kill_me; /* Set to nonzero to flag for termination */
+
+ const char *Pos; /* Our read position inside of the ReadBuf */
+ StrBuf *ReadBuf; /* Our block buffered read buffer */
+ StrBuf *MigrateBuf; /* Our block buffered read buffer */
+ int client_socket;
+ int is_local_socket; /* set to 1 if client is on unix domain sock */
+ /* Redirect this session's output to a memory buffer? */
+ char *redirect_buffer; /* the buffer */
+ size_t redirect_len; /* length of data in buffer */
+ size_t redirect_alloc; /* length of allocated buffer */
+#ifdef HAVE_OPENSSL
+ SSL *ssl;
+ int redirect_ssl;
+#endif
char curr_user[USERNAME_SIZE]; /* name of current user */
int logged_in; /* logged in */
int internal_pgm; /* authenticated as internal program */
int nologin; /* not allowed to log in */
- int is_local_socket; /* set to 1 if client is on unix domain sock */
int curr_view; /* The view type for the current user/room */
int is_master; /* Is this session logged in using the master user? */
time_t previous_login; /* Date/time of previous login */
char lastcmdname[5]; /* name of last command executed */
unsigned cs_flags; /* miscellaneous flags */
- void (*h_command_function) (void) ; /* service command function */
- void (*h_async_function) (void) ; /* do async msgs function */
- void (*h_greeting_function) (void) ; /* greeting function for session startup */
int is_async; /* Nonzero if client accepts async msgs */
int async_waiting; /* Nonzero if there are async msgs waiting */
int input_waiting; /* Nonzero if there is client input waiting */
/* Beginning of cryptography - session nonce */
char cs_nonce[NONCE_SIZE]; /* The nonce for this session's next auth transaction */
- /* Redirect this session's output to a memory buffer? */
- char *redirect_buffer; /* the buffer */
- size_t redirect_len; /* length of data in buffer */
- size_t redirect_alloc; /* length of allocated buffer */
-#ifdef HAVE_OPENSSL
- SSL *ssl;
- int redirect_ssl;
-#endif
/* A linked list of all instant messages sent to us. */
struct ExpressMessage *FirstExpressMessage;
const char *ServiceName; /* readable purpose of this session */
void *openid_data; /* Data stored by the OpenID module */
char *ldap_dn; /* DN of user when using AUTHMODE_LDAP */
+
+
+ void (*h_command_function) (void) ; /* service command function */
+ void (*h_async_function) (void) ; /* do async msgs function */
+ void (*h_greeting_function) (void) ; /* greeting function for session startup */
};
typedef struct CitContext CitContext;
/*
- * client_read_ssl() - read data from the encrypted layer.
+ * read data from the encrypted layer.
*/
-int client_read_ssl(char *buf, int bytes, int timeout)
+int client_read_sslbuffer(StrBuf *buf, int timeout)
{
-#if 0
- fd_set rfds;
- struct timeval tv;
- int retval;
- int s;
-#endif
- int len, rlen;
+ char sbuf[16384]; /* OpenSSL communicates in 16k blocks, so let's speak its native tongue. */
+ int rlen;
char junk[1];
+ SSL *pssl = CC->ssl;
- len = 0;
- while (len < bytes) {
-#if 0
- /*
- * This code is disabled because we don't need it when
- * using blocking reads (which we are). -IO
- */
- FD_ZERO(&rfds);
- s = BIO_get_fd(CC->ssl->rbio, NULL);
- FD_SET(s, &rfds);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- retval = select(s + 1, &rfds, NULL, NULL, &tv);
-
- if (FD_ISSET(s, &rfds) == 0) {
- return (0);
- }
+ if (pssl == NULL) return(-1);
-#endif
- if (SSL_want_read(CC->ssl)) {
- if ((SSL_write(CC->ssl, junk, 0)) < 1) {
- CtdlLogPrintf(CTDL_DEBUG, "SSL_write in client_read: %s\n", ERR_reason_error_string(ERR_get_error()));
+ while (1) {
+ if (SSL_want_read(pssl)) {
+ if ((SSL_write(pssl, junk, 0)) < 1) {
+ CtdlLogPrintf(CTDL_DEBUG, "SSL_write in client_read\n");
}
}
- rlen = SSL_read(CC->ssl, &buf[len], bytes - len);
+ rlen = SSL_read(pssl, sbuf, sizeof(sbuf));
if (rlen < 1) {
long errval;
- errval = SSL_get_error(CC->ssl, rlen);
- if (errval == SSL_ERROR_WANT_READ ||
- errval == SSL_ERROR_WANT_WRITE) {
+ errval = SSL_get_error(pssl, rlen);
+ if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
sleep(1);
continue;
}
CtdlLogPrintf(CTDL_DEBUG, "SSL_read got error %ld\n", errval);
endtls();
- return (client_read_to
- (&buf[len], bytes - len, timeout));
+ return (-1);
+ }
+ StrBufAppendBufPlain(buf, sbuf, rlen, 0);
+ return rlen;
+ }
+ return (0);
+}
+
+int client_readline_sslbuffer(StrBuf *Target, StrBuf *Buffer, int timeout)
+{
+ int ntries = 0;
+ const char *pch, *pchs;
+ int rlen, len, retval = 0;
+ CitContext *CCC = CC;
+
+ if (StrLength(Target) > 0) {
+ pchs = ChrPtr(Buffer);
+ pch = strchr(pchs, '\n');
+ if (pch != NULL) {
+ rlen = 0;
+ len = pch - pchs;
+ if (len > 0 && (*(pch - 1) == '\r') )
+ rlen ++;
+ StrBufSub(Target, Buffer, 0, len - rlen);
+ StrBufCutLeft(Buffer, len + 1);
+ return len - rlen;
+ }
+ }
+
+ while ((retval == 0) && (CCC->ssl != NULL)) {
+ pch = NULL;
+ pchs = ChrPtr(Buffer);
+ if (*pchs != '\0')
+ pch = strchr(pchs, '\n');
+ if (pch == NULL) {
+ retval = client_read_sslbuffer(Buffer, timeout);
+ pchs = ChrPtr(Buffer);
+ pch = strchr(pchs, '\n');
+ }
+ if (retval == 0) {
+ sleep(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, Buffer, 0, len - rlen);
+ StrBufCutLeft(Buffer, len + 1);
+ return len - rlen;
+
+ }
+ else
+ return -1;
+}
+
+
+
+int client_read_sslblob(StrBuf *Target, long bytes, int timeout)
+{
+ long bufremain;
+ long baselen;
+ int retval;
+ CitContext *CCC = CC;
+
+ baselen = StrLength(Target);
+
+ if (CCC->Pos == NULL)
+ CCC->Pos = ChrPtr(CCC->ReadBuf);
+ bufremain = StrLength(CCC->ReadBuf) -
+ (CCC->Pos - ChrPtr(CCC->ReadBuf));
+
+ if (bytes < bufremain)
+ bufremain = bytes;
+ StrBufAppendBufPlain(Target, CCC->Pos, bufremain, 0);
+ StrBufCutLeft(CCC->ReadBuf, bufremain);
+
+ if (bytes > bufremain)
+ {
+ while ((StrLength(CCC->ReadBuf) + StrLength(Target) < bytes + baselen) &&
+ (retval >= 0))
+ retval = client_read_sslbuffer(CCC->ReadBuf, timeout);
+ if (retval >= 0) {
+ StrBufAppendBuf(Target, CCC->ReadBuf, 0); /* todo: Buf > bytes? */
+ return 1;
+ }
+ else {
+ return -1;
}
- len += rlen;
}
- return (1);
+ else
+ return 1;
}
void destruct_ssl(void);
void init_ssl(void);
void client_write_ssl (const char *buf, int nbytes);
-int client_read_ssl (char *buf, int bytes, int timeout);
+int client_read_sslbuffer(StrBuf *buf, int timeout);
+int client_readline_sslbuffer(StrBuf *Target, StrBuf *Buffer, int timeout);
+int client_read_sslblob(StrBuf *Target, long want_len, int timeout);
void cmd_stls(char *params);
void cmd_gtls(char *params);
void endtls(void);
#endif
}
+static void flush_client_inbuf(void)
+{
+ CitContext *CCC=CC;
+
+ FlushStrBuf(CCC->ReadBuf);
+ CCC->Pos = NULL;
+}
/*
* client_write() ... Send binary data to the client.
CitContext *Ctx;
int fdflags;
+ flush_client_inbuf();
Ctx = CC;
if (Ctx->redirect_buffer != NULL) {
if ((Ctx->redirect_len + nbytes + 2) >= Ctx->redirect_alloc) {
/*
* Read data from the client socket.
- * Return values are:
- * 1 Requested number of bytes has been read.
- * 0 Request timed out.
- * -1 The socket is broken.
- * If the socket breaks, the session will be terminated.
+ *
+ * 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.
*/
-INLINE int client_read_backend(char *buf, int bytes, int timeout, CitContext *CCC)
+int client_read_blob(StrBuf *Target, int bytes, int timeout)
{
- int len,rlen;
- fd_set rfds;
- int fd;
- struct timeval tv;
- int retval;
+ CitContext *CCC=CC;
+ const char *Error;
+ int retval = 0;
#ifdef HAVE_OPENSSL
if (CCC->redirect_ssl) {
- return (client_read_ssl(buf, bytes, timeout));
+ retval = client_read_sslblob(Target, bytes, timeout);
}
+ else
#endif
- len = 0;
- fd = CCC->client_socket;
- while(len<bytes) {
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- retval = select( (fd)+1,
- &rfds, NULL, NULL, &tv);
- if (retval < 0)
- {
- if (errno == EINTR)
- {
- CtdlLogPrintf(CTDL_DEBUG, "Interrupted select() in client_read_to().\n");
- if (CtdlThreadCheckStop()) {
- CC->kill_me = 1;
- return (-1);
- } else {
- /* can't trust fd's and stuff so we need to re-create them */
- continue;
- }
- }
- else {
- CtdlLogPrintf(CTDL_DEBUG, "Failed select() in client_read_to().\n");
- CCC->kill_me = 1;
- return (-1);
- }
- }
-
- if (FD_ISSET(fd, &rfds) == 0) {
- return(0);
- }
- rlen = read(fd, &buf[len], bytes-len);
- if (rlen<1) {
- /* The socket has been disconnected! */
- CCC->kill_me = 1;
- return(-1);
- }
- len = len + rlen;
+ retval = StrBufReadBLOBBuffered(Target,
+ CCC->ReadBuf,
+ &CCC->Pos,
+ &CCC->client_socket,
+ 1,
+ bytes,
+ O_TERM,
+ &Error);
+ if (retval < 0) {
+ CtdlLogPrintf(CTDL_CRIT,
+ "%s failed: %s\n",
+ __FUNCTION__,
+ Error);
}
- return(1);
+ return retval;
}
-
int client_read_to(char *buf, int bytes, int timeout)
{
- return client_read_backend(buf, bytes, timeout, CC);
+ CitContext *CCC=CC;
+ int rc;
+
+ rc = client_read_blob(CCC->MigrateBuf, bytes, timeout);
+ if (rc < 0)
+ {
+ *buf = '\0';
+ return rc;
+ }
+ else
+ {
+ memcpy(buf,
+ ChrPtr(CCC->MigrateBuf),
+ StrLength(CCC->MigrateBuf) + 1);
+ FlushStrBuf(CCC->MigrateBuf);
+ return rc;
+ }
}
+
/*
* Read data from the client socket with default timeout.
* (This is implemented in terms of client_read_to() and could be
return(client_read_to(buf, bytes, config.c_sleeping));
}
+int CtdlClientGetLine(StrBuf *Target)
+{
+ CitContext *CCC=CC;
+ const char *Error;
+ int rc;
+
+#ifdef HAVE_OPENSSL
+ if (CCC->redirect_ssl) {
+ return client_readline_sslbuffer(Target,
+ CCC->ReadBuf,
+ 1);
+ }
+ else
+#endif
+ {
+ rc = StrBufTCP_read_buffered_line_fast(Target,
+ CCC->ReadBuf,
+ &CCC->Pos,
+ &CCC->client_socket,
+ 5,
+ 1,
+ &Error);
+ if ((rc < 0) && (Error != NULL))
+ CtdlLogPrintf(CTDL_CRIT,
+ "%s failed: %s\n",
+ __FUNCTION__,
+ Error);
+ return rc;
+ }
+}
+
/*
* client_getln() ... Get a LF-terminated line of text from the client.
{
int i, retval;
CitContext *CCC=CC;
+ const char *pCh;
- /* Read one character at a time.
- */
- for (i = 0;;i++) {
- retval = client_read_backend(&buf[i], 1, config.c_sleeping, CCC);
- if (retval != 1 || buf[i] == '\n' || i == (bufsize-1))
- break;
- }
-
- /* If we got a long line, discard characters until the newline.
- */
- if (i == (bufsize-1))
- while (buf[i] != '\n' && retval == 1)
- retval = client_read(&buf[i], 1);
+ retval = CtdlClientGetLine(CCC->MigrateBuf);
+ i = StrLength(CCC->MigrateBuf);
+ pCh = ChrPtr(CCC->MigrateBuf);
/* Strip the trailing LF, and the trailing CR if present.
*/
- buf[i] = 0;
+ if (bufsize <= i)
+ i = bufsize - 1;
while ( (i > 0)
- && ( (buf[i - 1]==13)
- || ( buf[i - 1]==10)) ) {
+ && ( (pCh[i - 1]==13)
+ || ( pCh[i - 1]==10)) ) {
i--;
- buf[i] = 0;
}
- if (retval < 0) safestrncpy(&buf[i], "000", bufsize - i);
- return(retval);
+ memcpy(buf, pCh, i);
+ buf[i] = 0;
+
+ FlushStrBuf(CCC->MigrateBuf);
+ if (retval < 0) {
+ safestrncpy(&buf[i], "000", bufsize - i);
+ }
+ return(retval >= 0);
}