Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4006130
  • 博文数量: 536
  • 博客积分: 10470
  • 博客等级: 上将
  • 技术积分: 4825
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-26 14:08
文章分类

全部博文(536)

文章存档

2024年(3)

2021年(1)

2019年(1)

2017年(1)

2016年(2)

2013年(2)

2012年(10)

2011年(43)

2010年(10)

2009年(17)

2008年(121)

2007年(252)

2006年(73)

分类:

2007-07-03 18:21:05

I have implemented sockets in kernel 2.6 and made simple functions like userspace. (I made for TCP but I think UDP can also be done in a similar manner)

Here is the complete code. I think the function names are self explanatory. First to use sockets, you have to create a struct socket objects.
For a server, use set_up_server_socket, followed by server_accept connection and for the client use set_up_client_socket. To send and recieve messages use the SendBuffer and RecvBuffer Functions.

/*
  Sendbuffer sends "Length" bytes from "Buffer" through the socket "sock".
 */

size_t SendBuffer(struct socket *sock, const char *Buffer, size_t Length)
{
  struct msghdr msg;
  mm_segment_t oldfs; // mm_segment_t is just a long

  struct iovec iov; // structure containing a base addr. and length

  int len2;

  //printk("Entering SendBuffer\n");


  msg.msg_name = 0;
  msg.msg_namelen = 0;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1; //point to be noted

  msg.msg_control = NULL;
  msg.msg_controllen = 0;

  msg.msg_flags = MSG_NOSIGNAL; //0/*MSG_DONTWAIT*/;


  iov.iov_base = (char*) Buffer; // as we know that iovec is

  iov.iov_len = (__kernel_size_t) Length; // nothing but a base addr and length


  // #define get_fs() (current_thread_info()->addr_limit)

  // similar for set_fs;


  /*
   Therefore this line sets the "fs" to KERNEL_DS and saves its old value
   */

  oldfs = get_fs();
  set_fs(KERNEL_DS);

  /* Actual Sending of the Message */
  len2 = sock_sendmsg(sock, &msg, (size_t)(Length));

  /* retrieve the old value of fs (whatever it is) */
  set_fs(oldfs);

  return len2;
}


/*
  Recieves data from the socket "sock" and puts it in the 'Buffer'.
  Returns the length of data recieved

  The Calling function must do a:
  Buffer = (char*) get_free_page(GFP_KERNEL);
  or a kmalloc to allocate kernel's memory
  (or it can use the kernel's stack space [very small] )
*/

size_t RecvBuffer(struct socket *sock, const char *Buffer, size_t Length)
{
  struct msghdr msg;
  struct iovec iov;
  int len;
  mm_segment_t oldfs;

  /* Set the msghdr structure*/
  msg.msg_name = 0;
  msg.msg_namelen = 0;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_flags = 0;

  /* Set the iovec structure*/
  iov.iov_base = (void *) &Buffer[0];
  iov.iov_len = (size_t)Length;

  /* Recieve the message */
  oldfs = get_fs();
  set_fs(KERNEL_DS);

  len = sock_recvmsg(sock,&msg,Length,0/*MSG_DONTWAIT*/); // let it wait if there is no message


  set_fs(oldfs);

  // if ((len!=-EAGAIN)&&(len!=0))

  // printk("RecvBuffer Recieved %i bytes \n",len);


  return len;
}

/*
  Sets up a server-side socket

  1. Create a new socket
  2. Bind the address to the socket
  3. Start listening on the socket
*/

struct socket* set_up_server_socket(int port_no)
{
  struct socket *sock;
  struct sockaddr_in sin;

  int error;

  /* First create a socket */
  error = sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&sock) ;
  if (error<0)
    printk("Error during creation of socket; terminating\n");

  /* Now bind the socket */
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = INADDR_ANY;
  sin.sin_port = htons(port_no);

  error = sock->ops->bind(sock,(struct sockaddr*)&sin,sizeof(sin));
  if (error<0)
  {
    printk("Error binding socket \n");
    return 0;
  }

  /* Now, start listening on the socket */
  error=sock->ops->listen(sock,32);
  if (error!=0)
    printk("Error listening on socket \n");

  /* Now start accepting */
  // Accepting is performed by the function server_accept_connection


  return sock;
}


/*
  Accepts a new connection (server calls this function)

  1. Create a new socket
  2. Call socket->ops->accept
  3. return the newly created socket
 */


struct socket* server_accept_connection(struct socket *sock)
{
  struct socket * newsock;
  int error;

  /* Before accept: Clone the socket */
  error = sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&newsock);
  if (error<0)
    printk("Error during creation of the other socket; terminating\n");

  newsock->type = sock->type;
  newsock->ops=sock->ops;

  /* Do the actual accept */
  error = newsock->ops->accept(sock,newsock,0);
  if (error<0)
  {
    /* must add release the socket code here */
    printk("Error accepting socket\n") ;
    return 0;
  }

  return newsock;
}

struct socket * set_up_client_socket(unsigned int IP_addr, int port_no)
{
  struct socket *clientsock;
  struct sockaddr_in sin;
  int error, i;

  /* First create a socket */
  error = sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&clien tsock);
  if (error<0)
  {
    printk("Error during creation of socket; terminating\n");
    return 0;
  }

  /* Now bind and connect the socket */
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = htonl(IP_addr);
  sin.sin_port = htons(port_no);

  for(i=0; i<10; i++)
  {
    error = clientsock->ops->connect(clientsock,(struct sockaddr*)&sin,sizeof(sin),0);
    if (error<0)
     {
      printk("Error connecting client socket to server: %i, retrying .. %d \n",error, i);
      if(i == 10-1)
        {
         printk("Giving Up!\n");
         return 0;
        }
     }
    else
      break; //connected

  }

  return clientsock;
}


部分地方写的还不是很规范, 但总的来说还是很不错, 可以学习学习!

Ref:
阅读(2921) | 评论(0) | 转发(0) |
0

上一篇:小金牛

下一篇:寻最佳数据存放格式!

给主人留下些什么吧!~~