--- /dev/null
+#
+# Makefile for CEPH kernel socket test.
+#
+
+obj-$(CONFIG_CEPHTESTS_FS) += ksocktest.o
+
+ksocktest-objs := kernclient.o messenger_mini.o ktcp.o
--- /dev/null
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/string.h>
+#include <net/tcp.h>
+
+#include <linux/ceph_fs.h>
+#include "messenger.h"
+#include "ktcp.h"
+
+
+#define PORT 9009
+#define HOST cranium
+#define cranium 192.168.1.3
+
+MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
+MODULE_DESCRIPTION("kernel thread test for Linux");
+MODULE_LICENSE("GPL");
+
+int work_init(void);
+void shutdown_workqueues(void);
+int add_sock_callbacks(struct socket *, struct ceph_connection *);
+int inet_aton (const char *cp, struct in_addr *addr);
+struct task_struct *thread;
+
+
+/*
+ * Wake up a thread when there is work to do
+ */
+/* void thread_wake_up(void)
+{
+}
+*/
+/*
+ * Client socket thread
+ */
+static int sock_thread(void *unusedfornow)
+{
+ struct ceph_messenger *msgr = NULL;
+ struct ceph_connection *con;
+ struct sockaddr_in saddr;
+ int ret;
+
+ printk(KERN_INFO "starting kernel thread\n");
+
+ con = new_connection(msgr);
+
+ /* inet_aton("192.168.1.3", &saddr.sin_addr); */
+ /* con->peer_addr.ipaddr.sin_addr = saddr.sin_addr; */
+
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ saddr.sin_port = htons(PORT);
+ printk(KERN_INFO "saddr info %p\n", &saddr);
+ con->peer_addr.ipaddr = saddr;
+
+
+ set_bit(WRITE_PEND, &con->state);
+
+ printk(KERN_INFO "about to connect to server\n");
+ /* connect to server */
+ if ((ret = do_connect(con))) {
+ printk(KERN_INFO "error connecting %d\n", ret);
+ goto done;
+ }
+ printk(KERN_INFO "connect succeeded\n");
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ /* an endless loop in which we are doing our work */
+ while (!kthread_should_stop())
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ printk(KERN_INFO "sock thread has been interrupted\n");
+ }
+
+ set_current_state(TASK_RUNNING);
+ sock_release(con->sock);
+done:
+ kfree(con);
+ printk(KERN_INFO "kernel thread exiting\n");
+ return 0;
+}
+
+static int __init init_kst(void)
+{
+ int ret;
+
+ printk(KERN_INFO "kernel thread test init\n");
+ /* create new kernel threads */
+ ret = work_init();
+ thread = kthread_run(sock_thread, NULL, "sock-thread");
+ if (IS_ERR(thread))
+ {
+ printk(KERN_INFO "failured to start kernel thread\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void __exit exit_kst(void)
+{
+ printk(KERN_INFO "kernel thread test exit\n");
+ shutdown_workqueues();
+ kthread_stop(thread);
+ wake_up_process(thread);
+
+ return;
+}
+
+
+module_init(init_kst);
+module_exit(exit_kst);
--- /dev/null
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <net/tcp.h>
+#include <linux/string.h>
+#include "messenger.h"
+#include "ktcp.h"
+
+
+struct socket * _kconnect(struct sockaddr *saddr)
+{
+ int ret;
+ struct socket *sd = NULL;
+
+ ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sd);
+ if (ret < 0) {
+ printk(KERN_INFO "sock_create_kern error: %d\n", ret);
+ return NULL;
+ }
+
+ ret = sd->ops->connect(sd, (struct sockaddr *) saddr,
+ sizeof (struct sockaddr_in),0);
+/*
+ ret = sd->ops->connect(sd, (struct sockaddr *) saddr,
+ sizeof (struct sockaddr_in),O_NONBLOCK);
+
+ if (ret == -EINPROGRESS) {
+ printk(KERN_INFO "non-blocking connect in progress: %d\n", ret);
+ goto done;
+ }
+*/
+
+ if (ret < 0) {
+ printk(KERN_INFO "kernel_connect error: %d\n", ret);
+ sock_release(sd);
+ }
+done:
+ return(sd);
+}
+
+struct socket * _klisten(struct sockaddr *saddr)
+{
+ int ret;
+ struct socket *sd = NULL;
+ struct sockaddr_in *in_addr = (struct sockaddr_in *)saddr;
+
+
+ ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sd);
+ if (ret < 0) {
+ printk(KERN_INFO "sock_create_kern error: %d\n", ret);
+ return(NULL);
+ }
+
+ /* no user specified address given so create, will allow arg to mount */
+ if (!in_addr->sin_addr.s_addr) {
+ in_addr->sin_family = AF_INET;
+ in_addr->sin_addr.s_addr = htonl(INADDR_ANY);
+ in_addr->sin_port = htons(CEPH_PORT); /* known port for now */
+ /* in_addr->sin_port = htons(0); */ /* any port */
+ }
+
+/* TBD: set sock options... */
+ /* ret = kernel_setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)optval, optlen);
+ if (ret < 0) {
+ printk("Failed to set SO_REUSEADDR: %d\n", ret);
+ } */
+ ret = sd->ops->bind(sd, saddr, sizeof(saddr));
+/* TBD: probaby want to tune the backlog queue .. */
+ ret = sd->ops->listen(sd, NUM_BACKUP);
+ if (ret < 0) {
+ printk(KERN_INFO "kernel_listen error: %d\n", ret);
+ sock_release(sd);
+ sd = NULL;
+ }
+ return(sd);
+}
+
+/*
+ * Note: Maybe don't need this, or make inline... keep for now for debugging..
+ * we may need to add more functionality
+ */
+struct socket *_kaccept(struct socket *sd)
+{
+ struct socket *new_sd = NULL;
+ int ret;
+
+
+ ret = kernel_accept(sd, &new_sd, sd->file->f_flags);
+ if (ret < 0) {
+ printk(KERN_INFO "kernel_accept error: %d\n", ret);
+ return(new_sd);
+ }
+/* TBD: shall we check name for validity? */
+ return(new_sd);
+}
+
+/*
+ * receive a message this may return after partial send
+ */
+int _krecvmsg(struct socket *sd, void *buf, size_t len, unsigned msgflags)
+{
+ struct kvec iov = {buf, len};
+ struct msghdr msg = {.msg_flags = msgflags};
+ int rlen = 0; /* length read */
+
+ printk(KERN_INFO "entered krevmsg\n");
+ msg.msg_flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
+
+ /* receive one kvec for now... */
+ rlen = kernel_recvmsg(sd, &msg, &iov, 1, len, msg.msg_flags);
+ if (rlen < 0) {
+ printk(KERN_INFO "kernel_recvmsg error: %d\n", rlen);
+ }
+ /* TBD: kernel_recvmsg doesn't fill in the name and namelen
+ */
+ return(rlen);
+
+}
+
+/*
+ * Send a message this may return after partial send
+ */
+int _ksendmsg(struct socket *sd, struct kvec *iov,
+ size_t kvlen, size_t len, unsigned msgflags)
+{
+ struct msghdr msg = {.msg_flags = msgflags};
+ int rlen = 0;
+
+ printk(KERN_INFO "entered ksendmsg\n");
+ msg.msg_flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
+
+ rlen = kernel_sendmsg(sd, &msg, iov, kvlen, len);
+ if (rlen < 0) {
+ printk(KERN_INFO "kernel_sendmsg error: %d\n", rlen);
+ }
+ return(rlen);
+}
+
+struct sockaddr *_kgetname(struct socket *sd)
+{
+ struct sockaddr *saddr = NULL;
+ int len;
+ int ret;
+
+ if ((ret = sd->ops->getname(sd, (struct sockaddr *)saddr,
+ &len, 2) < 0)) {
+ printk(KERN_INFO "kernel getname error: %d\n", ret);
+ }
+ return(saddr);
+
+}
--- /dev/null
+#ifndef _FS_CEPH_TCP_H
+#define _FS_CEPH_TCP_H
+
+/* prototype definitions */
+struct socket * _kconnect(struct sockaddr *);
+struct socket * _klisten(struct sockaddr *);
+struct socket *_kaccept(struct socket *);
+int _krecvmsg(struct socket *, void *, size_t , unsigned);
+int _ksendmsg(struct socket *, struct kvec *, size_t, size_t, unsigned);
+
+/* Well known port for ceph client listener.. */
+#define CEPH_PORT 2002
+/* Max number of outstanding connections in listener queueu */
+#define NUM_BACKUP 10
+#endif
--- /dev/null
+#ifndef __FS_CEPH_MESSENGER_H
+#define __FS_CEPH_MESSENGER_H
+
+#include <linux/uio.h>
+#include <linux/net.h>
+#include <linux/radix-tree.h>
+#include <linux/workqueue.h>
+#include <linux/ceph_fs.h>
+
+struct ceph_messenger {
+ struct socket *listen_sock; /* listening socket */
+ struct work_struct awork; /* accept work */
+ struct ceph_entity_inst inst; /* my name+address */
+ spinlock_t con_lock;
+ struct list_head con_all; /* all connections */
+};
+
+#define NEW 1
+#define CONNECTING 2
+#define ACCEPTING 3
+#define OPEN 4
+#define READ_PEND 5
+#define WRITE_PEND 6
+#define REJECTING 7
+#define CLOSED 8
+
+
+struct ceph_connection {
+ struct socket *sock; /* connection socket */
+ __u32 state;
+
+ atomic_t nref;
+ spinlock_t con_lock; /* connection lock */
+
+ struct list_head list_all; /* msgr->con_all */
+ struct ceph_entity_addr peer_addr; /* peer address */
+
+ char *buffer;
+
+ struct work_struct rwork; /* received work */
+ struct work_struct swork; /* send work */
+ int retries;
+ int error; /* error on connection */
+};
+
+
+struct ceph_connection *new_connection(struct ceph_messenger *);
+int do_connect(struct ceph_connection *con);
+#endif
--- /dev/null
+#include <linux/kthread.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/string.h>
+#include <net/tcp.h>
+
+#include <linux/ceph_fs.h>
+#include "messenger.h"
+#include "ktcp.h"
+
+static struct workqueue_struct *recv_wq; /* receive work queue */
+static struct workqueue_struct *send_wq; /* send work queue */
+
+static void try_read(struct work_struct *);
+static void try_write(struct work_struct *);
+static void try_accept(struct work_struct *);
+
+int add_sock_callbacks(struct socket *, struct ceph_connection *);
+
+
+/*
+ * connections
+ */
+
+/*
+ * create a new connection. initial state is NEW.
+ */
+struct ceph_connection *new_connection(struct ceph_messenger *msgr)
+{
+ struct ceph_connection *con;
+ con = kmalloc(sizeof(struct ceph_connection), GFP_KERNEL);
+ if (con == NULL)
+ return NULL;
+ memset(con, 0, sizeof(struct ceph_connection));
+
+ /* con->msgr = msgr; */
+
+ spin_lock_init(&con->con_lock);
+ INIT_WORK(&con->rwork, try_read); /* setup work structure */
+ INIT_WORK(&con->swork, try_write); /* setup work structure */
+
+ atomic_inc(&con->nref);
+ return con;
+}
+
+/*
+ * initiate connection to a remote socket.
+ *
+ */
+int do_connect(struct ceph_connection *con)
+{
+ struct sockaddr *paddr = (struct sockaddr *)&con->peer_addr.ipaddr;
+ int ret = 0;
+
+
+ set_bit(CONNECTING, &con->state);
+
+ ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &con->sock);
+ if (ret < 0) {
+ printk(KERN_INFO "sock_create_kern error: %d\n", ret);
+ goto done;
+ }
+
+ /* setup callbacks */
+ add_sock_callbacks(con->sock, con);
+
+
+ ret = con->sock->ops->connect(con->sock, paddr,
+ sizeof(struct sockaddr_in),O_NONBLOCK);
+ if (ret == -EINPROGRESS) return 0;
+ if (ret < 0) {
+ /* TBD check for fatal errors, retry if not fatal.. */
+ printk(KERN_INFO "kernel_connect error: %d\n", ret);
+ sock_release(con->sock);
+ con->sock = NULL;
+ }
+done:
+ printk(KERN_INFO "do_connect state = %u\n", con->state);
+ return ret;
+}
+
+/*
+ * call when socket is writeable
+ */
+static void try_write(struct work_struct *work)
+{
+ struct ceph_connection *con;
+ struct kvec iov;
+ int ret;
+
+
+
+ con = container_of(work, struct ceph_connection, swork);
+
+ printk(KERN_INFO "Entered try_write state = %u\n", con->state);
+
+ clear_bit(WRITE_PEND, &con->state);
+ set_bit(READ_PEND, &con->state);
+
+
+ con->buffer = kzalloc(256, GFP_KERNEL);
+ if (con->buffer == NULL)
+ goto done;
+
+ strcpy(con->buffer, "hello world");
+ iov.iov_base = con->buffer;
+ iov.iov_len = 255;
+ printk(KERN_INFO "about to send message\n");
+ ret = _ksendmsg(con->sock,&iov,1,iov.iov_len,0);
+ if (ret < 0) goto done;
+ printk(KERN_INFO "wrote %d bytes to server\n", ret);
+
+
+
+ kfree(con->buffer);
+done:
+ return;
+}
+
+
+/*
+ * call when data is available on the socket
+ */
+static void try_read(struct work_struct *work)
+{
+ struct ceph_connection *con;
+ int len;
+
+
+ con = container_of(work, struct ceph_connection, rwork);
+
+ printk(KERN_INFO "Entered try_read state = %u\n", con->state);
+
+ con->buffer = kzalloc(256, GFP_KERNEL);
+ if (con->buffer == NULL)
+ goto done;
+
+ len = _krecvmsg(con->sock,con->buffer,255,0);
+ if (len < 0){
+ printk(KERN_INFO "ERROR reading from socket\n");
+ goto done;
+ }
+ printk(KERN_INFO "received message: %s\n", con->buffer);
+ printk(KERN_INFO "message length: %d\n", len);
+
+ kfree(con->buffer);
+done:
+ return;
+}
+
+
+/*
+ * Accepter thread
+ */
+static void try_accept(struct work_struct *work)
+{
+ struct socket *sock, *new_sock;
+ struct sockaddr_in saddr;
+ struct ceph_connection *new_con = NULL;
+ struct ceph_messenger *msgr;
+ int len;
+
+ msgr = container_of(work, struct ceph_messenger, awork);
+ sock = msgr->listen_sock;
+
+
+ printk(KERN_INFO "Entered try_accept\n");
+
+
+ if (kernel_accept(sock, &new_sock, sock->file->f_flags) < 0) {
+ printk(KERN_INFO "error accepting connection \n");
+ goto done;
+ }
+ printk(KERN_INFO "accepted connection \n");
+
+ /* get the address at the other end */
+ memset(&saddr, 0, sizeof(saddr));
+ if (new_sock->ops->getname(new_sock, (struct sockaddr *)&saddr, &len, 2)) {
+ printk(KERN_INFO "getname error connection aborted\n");
+ sock_release(new_sock);
+ goto done;
+ }
+
+ /* initialize the msgr connection */
+ new_con = new_connection(msgr);
+ if (new_con == NULL) {
+ printk(KERN_INFO "malloc failure\n");
+ sock_release(new_sock);
+ goto done;
+ }
+ new_con->sock = new_sock;
+ set_bit(ACCEPTING, &new_con->state);
+ /* new_con->in_tag = CEPH_MSGR_TAG_READY; */
+ /* fill in part of peers address */
+ new_con->peer_addr.ipaddr = saddr;
+
+ /* hand off to worker threads , send pending */
+ /*?? queue_work(send_wq, &new_con->swork);*/
+done:
+ return;
+}
+
+/*
+ * create a new messenger instance, saddr is address specified from mount arg.
+ * If null, will get created by _klisten()
+ */
+struct ceph_messenger *ceph_create_messenger(struct sockaddr *saddr)
+{
+ struct ceph_messenger *msgr;
+
+ msgr = kmalloc(sizeof(*msgr), GFP_KERNEL);
+ if (msgr == NULL)
+ return NULL;
+ memset(msgr, 0, sizeof(*msgr));
+
+ spin_lock_init(&msgr->con_lock);
+
+ /* create listening socket */
+ msgr->listen_sock = _klisten(saddr);
+ if (msgr->listen_sock == NULL) {
+ kfree(msgr);
+ return NULL;
+ }
+ /* TBD: setup callback for accept */
+ INIT_WORK(&msgr->awork, try_accept); /* setup work structure */
+ return msgr;
+}
+
+/* Data available on socket or listen socket received a connect */
+static void ceph_data_ready(struct sock *sk, int count_unused)
+{
+ struct ceph_connection *con = (struct ceph_connection *)sk->sk_user_data;
+
+ printk(KERN_INFO "Entered ceph_data_ready state = %u\n", con->state);
+ if (test_bit(READ_PEND, &con->state)) {
+ printk(KERN_INFO "READ_PEND set in connection\n");
+ queue_work(recv_wq, &con->rwork);
+ }
+}
+
+static void ceph_write_space(struct sock *sk)
+{
+ struct ceph_connection *con = (struct ceph_connection *)sk->sk_user_data;
+
+ printk(KERN_INFO "Entered ceph_write_space state = %u\n",con->state);
+ if (test_bit(WRITE_PEND, &con->state)) {
+ printk(KERN_INFO "WRITE_PEND set in connection\n");
+ queue_work(send_wq, &con->swork);
+ }
+}
+
+static void ceph_state_change(struct sock *sk)
+{
+ struct ceph_connection *con = (struct ceph_connection *)sk->sk_user_data;
+ /* TBD: probably want to set our connection state to OPEN
+ * if state not set to READ or WRITE pending
+ */
+ printk(KERN_INFO "Entered ceph_state_change state = %u\n", con->state);
+ if (sk->sk_state == TCP_ESTABLISHED) {
+ if (test_and_clear_bit(CONNECTING, &con->state))
+ set_bit(OPEN, &con->state);
+ ceph_write_space(sk);
+ }
+}
+
+/* Make a socket active */
+int add_sock_callbacks(struct socket *sock, struct ceph_connection *con)
+{
+ struct sock *sk = sock->sk;
+ sk->sk_user_data = con;
+ printk(KERN_INFO "Entered add_sock_callbacks\n");
+
+ /* Install callbacks */
+ sk->sk_data_ready = ceph_data_ready;
+ sk->sk_write_space = ceph_write_space;
+ sk->sk_state_change = ceph_state_change;
+
+ return 0;
+}
+
+/*
+ * workqueue initialization
+ */
+
+int work_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "entered work_init\n");
+ /*
+ * Create a num CPU threads to handle receive requests
+ * note: we can create more threads if needed to even out
+ * the scheduling of multiple requests..
+ */
+ recv_wq = create_workqueue("ceph-recv");
+ ret = IS_ERR(recv_wq);
+ if (ret) {
+ printk(KERN_INFO "receive worker failed to start: %d\n", ret);
+ destroy_workqueue(recv_wq);
+ return ret;
+ }
+
+ /*
+ * Create a single thread to handle send requests
+ * note: may use same thread pool as receive workers later...
+ */
+ send_wq = create_singlethread_workqueue("ceph-send");
+ ret = IS_ERR(send_wq);
+ if (ret) {
+ printk(KERN_INFO "send worker failed to start: %d\n", ret);
+ destroy_workqueue(send_wq);
+ return ret;
+ }
+ printk(KERN_INFO "successfully created wrkqueues\n");
+
+ return(ret);
+}
+
+/*
+ * workqueue shutdown
+ */
+void shutdown_workqueues(void)
+{
+ destroy_workqueue(send_wq);
+ destroy_workqueue(recv_wq);
+}
--- /dev/null
+#include <linux/module.h>
+#include <linux/kthread.h>
+
+MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
+MODULE_DESCRIPTION("kernel thread test for Linux");
+MODULE_LICENSE("GPL");
+
+#define NTHREADS 3
+struct task_struct *thread[3];
+/* static DECLARE_WAIT_QUEUE_HEAD(dispatch_wait); */
+
+/*
+ * Wake up a thread when there is work to do
+ */
+/* void thread_wake_up(void)
+{
+}
+*/
+
+static int dispatch_thread(void *unusedfornow)
+{
+ printk(KERN_INFO "starting kernel thread\n");
+ set_current_state(TASK_INTERRUPTIBLE);
+ /* an endless loop in which we are doing our work */
+ while (!kthread_should_stop())
+ {
+ schedule();
+ printk(KERN_INFO "Dispatch thread has been interrupted\n");
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ printk(KERN_INFO "kernel thread exiting\n");
+ return 0;
+}
+
+static int __init init_kst(void)
+{
+ int i;
+
+ printk(KERN_INFO "kernel thread test init\n");
+ /* create new kernel threads */
+ for (i=0; i < NTHREADS; i++) {
+ thread[i] = kthread_run(dispatch_thread, NULL, "dispatcher thread");
+ if (IS_ERR(thread[i]))
+ {
+ printk(KERN_INFO "failured to start kernel thread\n");
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static void __exit exit_kst(void)
+{
+ int i;
+
+ printk(KERN_INFO "kernel thread test exit\n");
+ for (i=0; i <NTHREADS; i++) {
+ kthread_stop(thread[i]);
+ wake_up_process(thread[i]);
+ }
+
+ return;
+}
+
+
+module_init(init_kst);
+module_exit(exit_kst);
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+int main(int argc, char *argv[])
+{
+ int sd, port,len;
+ struct sockaddr_in saddr;
+ struct hostent *server;
+ char buf[256];
+
+ if (argc < 3) {
+ fprintf(stderr,"usage %s hostname port\n", argv[0]);
+ exit(1);
+ }
+ port = atoi(argv[2]);
+ printf("port num = %d\n", port);
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sd < 0) {
+ fprintf(stderr,"socket open error");
+ exit(1);
+ }
+ server = gethostbyname(argv[1]);
+ printf("server name = %s\n", server->h_name);
+ printf("server ip = %s\n", *(server->h_addr));
+ if (server == NULL) {
+ fprintf(stderr,"get host error\n");
+ exit(1);
+ }
+ bzero((char *) &saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ bcopy((char *)server->h_addr, (char *)&saddr.sin_addr.s_addr,
+ server->h_length);
+ saddr.sin_port = htons(port);
+ if (connect(sd,(struct sockaddr *)&saddr,sizeof(saddr)) < 0) {
+ fprintf(stderr,"connection error\n");
+ exit(1);
+ }
+ printf("Please enter the message: ");
+ bzero(buf,256);
+ fgets(buf,255,stdin);
+ len = write(sd,buf,strlen(buf));
+ if (len < 0) {
+ fprintf(stderr,"write error\n");
+ exit(1);
+ }
+ bzero(buf,256);
+ len = read(sd,buf,255);
+ if (len < 0) {
+ fprintf(stderr,"write error\n");
+ exit(1);
+ }
+ printf("received message %s\n",buf);
+ close(sd);
+ exit(0);
+}
--- /dev/null
+/* note: port number is passed as an argument */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_in saddr, caddr;
+ int sd, new_sd, port, clen, numbytes;
+ char buf[256];
+
+ if (argc < 2) {
+ fprintf(stderr,"error must enter port \n");
+ exit(1);
+ }
+ printf("starting server\n");
+
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sd < 0) {
+ fprintf(stderr,"error creating socket\n");
+ exit(1);
+ }
+ bzero((char *) &saddr, sizeof(struct sockaddr_in));
+ port = atoi(argv[1]);
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = INADDR_ANY;
+ saddr.sin_port = htons(port);
+ if (bind(sd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
+ fprintf(stderr,"bind error\n");
+ exit(1);
+ }
+ listen(sd,5);
+ printf("started listening\n");
+ clen = sizeof(caddr);
+ new_sd = accept(sd, (struct sockaddr *) &caddr, &clen);
+ if (new_sd < 0) {
+ fprintf(stderr,"accept error\n");
+ exit(1);
+ }
+ printf("accepted connection\n");
+ bzero(buf,256);
+ numbytes = read(new_sd,buf,255);
+ if (numbytes < 0) {
+ fprintf(stderr,"read error\n");
+ exit(1);
+ }
+ printf("Message received: %s\n",buf);
+ strcpy(buf,"server received your message");
+ numbytes = write(new_sd, buf, 255);
+ if (numbytes < 0){
+ fprintf(stderr,"write error\n");
+ exit(1);
+ }
+ close(new_sd);
+ close(sd);
+ exit(0);
+}
+