summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2013-10-22 23:42:22 +0800
committerLAN-TW <lantw44@gmail.com>2013-10-22 23:42:22 +0800
commita490b98a996d16aa9544f7144e02034c04c50f59 (patch)
treed347ea2df51758840b944e9e2101f4cf469a94dc
parent5b0ecafc3d5f8312755ae59057e6de413516098f (diff)
downloadcn2013-a490b98a996d16aa9544f7144e02034c04c50f59.tar.gz
cn2013-a490b98a996d16aa9544f7144e02034c04c50f59.tar.zst
cn2013-a490b98a996d16aa9544f7144e02034c04c50f59.zip
HW1: 實作登入 RasSession 用的讀入一行的指令
-rw-r--r--hw1/connection.c1
-rw-r--r--hw1/server-main.c2
-rw-r--r--hw1/session.c75
-rw-r--r--hw1/session.h22
-rw-r--r--hw1/socktool.c120
-rw-r--r--hw1/socktool.h22
-rw-r--r--hw1/xwrap.c13
-rw-r--r--hw1/xwrap.h3
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, ...);