diff options
author | LAN-TW <lantw44@gmail.com> | 2013-10-22 23:42:22 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2013-10-22 23:42:22 +0800 |
commit | a490b98a996d16aa9544f7144e02034c04c50f59 (patch) | |
tree | d347ea2df51758840b944e9e2101f4cf469a94dc | |
parent | 5b0ecafc3d5f8312755ae59057e6de413516098f (diff) | |
download | cn2013-a490b98a996d16aa9544f7144e02034c04c50f59.tar.gz cn2013-a490b98a996d16aa9544f7144e02034c04c50f59.tar.zst cn2013-a490b98a996d16aa9544f7144e02034c04c50f59.zip |
HW1: 實作登入 RasSession 用的讀入一行的指令
-rw-r--r-- | hw1/connection.c | 1 | ||||
-rw-r--r-- | hw1/server-main.c | 2 | ||||
-rw-r--r-- | hw1/session.c | 75 | ||||
-rw-r--r-- | hw1/session.h | 22 | ||||
-rw-r--r-- | hw1/socktool.c | 120 | ||||
-rw-r--r-- | hw1/socktool.h | 22 | ||||
-rw-r--r-- | hw1/xwrap.c | 13 | ||||
-rw-r--r-- | hw1/xwrap.h | 3 |
8 files changed, 241 insertions, 17 deletions
diff --git a/hw1/connection.c b/hw1/connection.c index 77281af..b7bd650 100644 --- a/hw1/connection.c +++ b/hw1/connection.c @@ -47,7 +47,6 @@ int ras_conn_init ( } char* dir_sep_loc = strrchr (name, '/'); - char* id_to_str; if (dir_sep_loc != NULL) { name = dir_sep_loc + 1; } diff --git a/hw1/server-main.c b/hw1/server-main.c index 89c2576..4a7bfb0 100644 --- a/hw1/server-main.c +++ b/hw1/server-main.c @@ -156,7 +156,7 @@ int main (int argc, char* argv[]) { } else if (cpid > 0) { /* parent process: just close the accepted fd */ ras_server_log (server, - "client %d is handled by process %u now", cid, cpid); + "client %d is handled by process %u", cid, cpid); cid++; close (session_fd); } else { diff --git a/hw1/session.c b/hw1/session.c index 33b5d39..dd416a8 100644 --- a/hw1/session.c +++ b/hw1/session.c @@ -4,10 +4,19 @@ #include "session.h" -#include "server.h" +#include "xwrap.h" +#include "socktool.h" #include "connection.h" +#include "server.h" +#include <errno.h> +#include <grp.h> +#include <pwd.h> #include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> int ras_session_init (RasSession* session, RasServer* server, int fd, int id) { /* chain up to parent constructor */ @@ -26,6 +35,11 @@ int ras_session_init (RasSession* session, RasServer* server, int fd, int id) { RAS_CONN (session)->fd = fd; RAS_CONN (session)->fd_is_set = true; + ras_socktool_buffer_clear (&session->buffer, true); + session->shell_pid = 0; + session->shell_stdio = -1; + session->shell_use_pty = true; + ras_session_log (session, "session started"); return 0; @@ -33,12 +47,71 @@ int ras_session_init (RasSession* session, RasServer* server, int fd, int id) { void ras_session_destroy (RasSession* session) { ras_session_log (session, "session closed"); + ras_socktool_buffer_clear (&session->buffer, false); /* chain up to parent destructor */ ras_conn_destroy (RAS_CONN (session)); } +char* ras_session_getline (RasSession* session, int* len) { + char* newline; + session->buffer.buf_error = false; + session->buffer.buf_eof = false; + while ((newline = ras_socktool_getline ( + RAS_CONN (session)->fd, &session->buffer, '\n', len)) == NULL && + !(session->buffer.buf_error) && !(session->buffer.buf_eof)); + return newline; +} + int ras_session_read_header (RasSession* session) { + int onelinelen; + char* oneline = ras_session_getline (session, &onelinelen); + char* space; + char* next; + + ras_socktool_buffer_free_line (&session->buffer); + if (session->buffer.buf_error) { + free (oneline); + ras_session_log (session, "read error: %s", strerror (errno)); + return -1; + } + if (session->buffer.buf_eof) { + free (oneline); + ras_session_log (session, "connection closed by peer"); + return -1; + } + + const char usage_msg[] = + "Usage: LOGIN [USERNAME] (login without allocating a pseudo-tty)\n" + " or: LOGINTTY [USERNAME] (login and allocate a pseudo-tty)\n" + "If USERNAME is not specified, system default will be used.\n"; + const int usage_len = STATIC_STRLEN (usage_msg); + + space = strchr (oneline, ' '); + if (space == NULL) { + next = oneline + onelinelen; + } else { + *space = '\0'; + for (space++; *space != '\0' && *space != ' '; space++); + next = space; + } + + if (strcmp (oneline, "LOGIN") == 0) { + session->shell_use_pty = false; + } else if (strcmp (oneline, "LOGINTTY") == 0) { + session->shell_use_pty = true; + } else { + const char badcmd_msg[] = "Error: Unknown login command.\n"; + const int badcmd_len = STATIC_STRLEN (badcmd_msg); + ras_socktool_write_string (RAS_CONN (session)->fd, badcmd_msg, badcmd_len); + ras_socktool_write_string (RAS_CONN (session)->fd, usage_msg, usage_len); + ras_session_log (session, "command %s is not understood", oneline); + free (oneline); + return -1; + } + + + return 0; } int ras_session_start_shell (RasSession* session) { diff --git a/hw1/session.h b/hw1/session.h index 3ceeba8..566157f 100644 --- a/hw1/session.h +++ b/hw1/session.h @@ -1,27 +1,27 @@ #ifndef RAS_SESSION_H #define RAS_SESSION_H +#include "socktool.h" #include "connection.h" #include "server.h" #include <sys/types.h> #define RAS_SESSION(x) ((RasSession*)(x)) -#define RAS_SESSION_BUFFER_SIZE 8192 typedef struct { - RasConn conn; - pid_t shell_pid; - int shell_stdio; - char buf[RAS_SESSION_BUFFER_SIZE]; - int buf_start; - int buf_len; + RasConn conn; + RasBuffer buffer; + pid_t shell_pid; + int shell_stdio; + int shell_use_pty : 1; } RasSession; -int ras_session_init (RasSession* sesssion, RasServer* server, int fd, int cid); -void ras_session_destroy (RasSession* session); -int ras_session_read_header (RasSession* session); -int ras_session_start_shell (RasSession* session); +int ras_session_init (RasSession* sesssion, RasServer* server, int fd, int cid); +void ras_session_destroy (RasSession* session); +char* ras_session_getline (RasSession* session, int* len); +int ras_session_read_header (RasSession* session); +int ras_session_start_shell (RasSession* session); /* Access parent methods */ #define ras_session_log(x, ...) ras_conn_log(RAS_CONN(x), __VA_ARGS__) diff --git a/hw1/socktool.c b/hw1/socktool.c index a705e3c..c554775 100644 --- a/hw1/socktool.c +++ b/hw1/socktool.c @@ -6,17 +6,21 @@ #include "xwrap.h" #include <arpa/inet.h> +#include <errno.h> #include <netinet/in.h> +#include <stdbool.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> +#include <unistd.h> -char* ras_socktool_get_peername (int sockfd) { +typedef int (*SockNameGetter) (int, struct sockaddr*, socklen_t*); +static char* ras_socktool_get_name (int sockfd, SockNameGetter getter) { struct sockaddr_storage sock; socklen_t socklen = sizeof (sock); memset (&sock, 0, socklen); - if (getpeername (sockfd, SOCKADDR (&sock), &socklen) < 0) { + if ((*getter)(sockfd, SOCKADDR (&sock), &socklen) < 0) { return xstrdup ("invalid socket"); } @@ -44,3 +48,115 @@ char* ras_socktool_get_peername (int sockfd) { return ipstr; } + +char* ras_socktool_get_sockname (int sockfd) { + return ras_socktool_get_name (sockfd, getsockname); +} + +char* ras_socktool_get_peername (int sockfd) { + return ras_socktool_get_name (sockfd, getpeername); +} + +void ras_socktool_buffer_clear (RasBuffer* buf, bool initial) { + buf->buf_start = 0; + buf->buf_len = 0; + + if (!initial) { + free (buf->buf_line); + } + buf->buf_line = NULL; + buf->buf_line_len = 0; + buf->buf_error = false; + buf->buf_eof = false; +} + +void ras_socktool_buffer_free_line (RasBuffer* buf) { + free (buf->buf_line); + buf->buf_line = NULL; + buf->buf_line_len = 0; +} + +char* ras_socktool_getline (int sockfd, RasBuffer* buf, int delim, int* len) { + if (buf->buf_error || buf->buf_eof) { + return NULL; + } + + if (buf->buf_len == 0) { + int rval = read (sockfd, buf->buf, RAS_BUFFER_SIZE); + if (rval < 0) { + if (errno != EAGAIN && errno != EINTR) { + buf->buf_error = true; + } + return NULL; + } + if (rval == 0) { + buf->buf_eof = true; + return NULL; + } + buf->buf_start = 0; + buf->buf_len = rval; + } + + int i; + for (i = 0; i < buf->buf_len; i++) { + if (buf->buf[buf->buf_start + i] == delim) { + break; + } + } + + int buf_line_start = buf->buf_line_len; + buf->buf_line_len += i; + buf->buf_line = xrealloc (buf->buf_line, buf->buf_line_len + 1); + memcpy (buf->buf_line + buf_line_start, buf->buf + buf->buf_start, i); + buf->buf_line[buf->buf_line_len] = '\0'; + + /* remove CR if delim is LF and delim is found */ + if (i < buf->buf_len && delim == '\n' && buf->buf_line_len - 1 >= 0 && + buf->buf_line[buf->buf_line_len - 1] == '\r') { + buf->buf_line[buf->buf_line_len - 1] = '\0'; + buf->buf_line_len--; + } + + int buf_len_saved = buf->buf_len; + buf->buf_start += i + 1; + buf->buf_len -= i + 1; + if (buf->buf_len <= 0) { + buf->buf_start = 0; + buf->buf_len = 0; + } + + if (i < buf_len_saved) { + /* delim is found */ + char* newstr = buf->buf_line; + if (len != NULL) { + *len = buf->buf_line_len; + } + buf->buf_line = NULL; + buf->buf_line_len = 0; + return newstr; + } + + return NULL; +} + +int ras_socktool_write_string (int sockfd, const char* str, size_t size) { + size_t wtn = 0; + size_t rem = size; + if (size <= 0) { + size = strlen (str); + } + while (rem > 0) { + wtn = write (sockfd, str, rem); + if (wtn < 0) { + if (errno != EINTR && errno != EAGAIN) { + break; + } + continue; + } + str += wtn; + rem -= wtn; + } + + rem = rem > 0 ? rem : 0; + return size - rem; +} diff --git a/hw1/socktool.h b/hw1/socktool.h index 13a60b6..4cf4383 100644 --- a/hw1/socktool.h +++ b/hw1/socktool.h @@ -1,11 +1,33 @@ #ifndef RAS_SOCKTOOL_H #define RAS_SOCKTOOL_H +#include <stdbool.h> +#include <sys/types.h> + #define SOCKADDR(x) ((struct sockaddr*)(x)) #define SOCKADDR_UN(x) ((struct sockaddr_un*)(x)) #define SOCKADDR_IN(x) ((struct sockaddr_in*)(x)) #define SOCKADDR_IN6(x) ((struct sockaddr_in6*)(x)) +char* ras_socktool_get_sockname (int sockfd); char* ras_socktool_get_peername (int sockfd); + +#define RAS_BUFFER_SIZE 8192 + +typedef struct { + char buf[RAS_BUFFER_SIZE]; + off_t buf_start; + off_t buf_len; + char* buf_line; + size_t buf_line_len; + int buf_error : 1; + int buf_eof : 1; +} RasBuffer; + +void ras_socktool_buffer_clear (RasBuffer* buf, bool initial); +void ras_socktool_buffer_free_line (RasBuffer* buf); +char* ras_socktool_getline (int sockfd, RasBuffer* buf, int delim, int* len); +int ras_socktool_write_string (int sockfd, const char* str, size_t size); + #endif /* RAS_SOCKTOOL_H */ diff --git a/hw1/xwrap.c b/hw1/xwrap.c index 3d56000..4999ec7 100644 --- a/hw1/xwrap.c +++ b/hw1/xwrap.c @@ -15,7 +15,7 @@ #define RETRY_NSEC 250000000 static const char fail_msg[] = "Fail to allocate memory. Retry ...\n"; -static const size_t fail_len = sizeof (fail_msg) / sizeof (char) - 1; +static const size_t fail_len = STATIC_STRLEN (fail_msg); void* xmalloc (size_t size) { void* memptr; @@ -28,6 +28,17 @@ void* xmalloc (size_t size) { return memptr; } +void* xrealloc (void* ptr, size_t size) { + void* newptr; + + while ((newptr = realloc (ptr, size)) == NULL) { + nanosleep (&(struct timespec) { RETRY_SEC, RETRY_NSEC }, NULL); + write (STDERR_FILENO, fail_msg, fail_len); + } + + return newptr; +} + char* xstrcat (const char* str, ...) { va_list ap; char* strp; diff --git a/hw1/xwrap.h b/hw1/xwrap.h index 58dd05c..5a0e0f6 100644 --- a/hw1/xwrap.h +++ b/hw1/xwrap.h @@ -3,7 +3,10 @@ #include <stdlib.h> +#define STATIC_STRLEN(x) (sizeof(x)/sizeof(char) - 1) + void* xmalloc (size_t size); +void* xrealloc (void* ptr, size_t size); char* xstrcat (const char* str, ...); char* xstrdup (const char* str); char* xsprintf (const char* format, ...); |