读核日记socket篇

发表于:2007-07-04来源:作者:点击数: 标签:
今天被一个sock_fd的值的问题折磨了半天 靠,干脆花了1个小时看了一下内核 貌似效果不错,做个笔记 pblog的缩进还挺麻烦的,不管它了 可以直接找我要文件,如果看起来不爽的话 /* 网络 编程中要注意描述符的边界问题 比如socket描述符等 描述符等于0的情况也

今天被一个sock_fd的值的问题折磨了半天

靠,干脆花了1个小时看了一下内核

貌似效果不错,做个笔记

pblog的缩进还挺麻烦的,不管它了

可以直接找我要文件,如果看起来不爽的话

/*
网络编程中要注意描述符的边界问题

比如socket描述符等

描述符等于0的情况也是正常的

if (sock >= 0) //应该按照 sock >= 0的情况来判断
 ...

如果是
if (sock > 0)
 ... //可能出现的问题是,tcp连接不能建立,包不能正确传送或者不能传送
 
值为0属于正常情况

我考,看socket源代码,日

socket也是加入系统标用表中的系统函数,参考 /kernel/sys.c
*/

// /net/core/sock.c
// /net/socket.c

/* 入口函数 sys_socket();
 * 原型: asmlinkage long sys_socket(int family, int type, int protocol);
 * 调用函数 socket();
 * 原型: int socket(int domain, int type, int protocol);
 * 两者应该是对应起来的
 * 取值范围
 * 参考 /include/linux/socket.h address family的两组宏定义 */
asmlinkage long sys_socket(int family, int type, int protocol)
{
 int retval;
 struct socket *sock;

 //创建socket,由此可以看出socket是非负整数值
 retval = sock_create(family, type, protocol, &sock);
 if (retval < 0)
  goto out;

 //加入描述符表,呵呵
 retval = sock_map_fd(sock);
 if (retval < 0)
  goto out_release; //这会已经分配了socket,所以返回前要释放资源

out:
 /* It may be already another descriptor 8) Not kernel problem. */
 // 正常返回,创建失败返回
 return retval;

out_release:
 sock_release(sock);
 return retval;
}

/* sock_create 最终调用到 函数 __sock_create()
 * 函数名字前面加两个dash的表示系统内部函数
 *
 *
 */
static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)
{
 int i;
 int err;
 struct socket *sock;

 /*
  * Check protocol is in range
  */
 if (family < 0 || family >= NPROTO)
  return -EAFNOSUPPORT;
 if (type < 0 || type >= SOCK_MAX)
  return -EINVAL;

 /* Compatibility.

    // ugly 丑陋的
    // moron 低能,白痴
    // 避免加载模块时死锁
    This uglymoron is moved from INET layer to here to avoid
    deadlock in module load.
  */
 // 协议族参考 /include/asm-i386/socket.h
 if (family == PF_INET && type == SOCK_PACKET) {//PF_INET == AF_INET --> Internet IP Protocol
  static int warned;
  if (!warned) {
   warned = 1;
   printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)n", current->comm);
  }
  family = PF_PACKET; //packet family
 }

        //是否和filter结合在一起的? 
 err = security_socket_create(family, type, protocol, kern);
 if (err)
  return err;
  
#if defined(CONFIG_KMOD)
 /* Attempt to load a protocol module if the find failed.
  *
  * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
  * requested real, full-featured networking support upon configuration.
  * Otherwise module support will break!
  */
 if (net_families[family]==NULL)
 {
  request_module("net-pf-%d",family);
 }
#endif

 net_family_read_lock();
 if (net_families[family] == NULL) {
  i = -EAFNOSUPPORT;
  goto out;
 }

/*
 * Allocate the socket and allow the family to set things up. if
 * the protocol is 0, the family is instructed to select an appropriate
 * default.
 */
        //分配资源,日哦,分配inode
 if (!(sock = sock_alloc()))
 {
  printk(KERN_WARNING "socket: no more socketsn");
  i = -ENFILE;  /* Not exactly a match, but its the
        closest posix thing */
  goto out;
 }

 //赋值啦
 sock->type  = type;

 //refcnt 引用计数器
 /*
  * We will call the ->create function, that possibly is in a loadable
  * module, so we have to bump that loadable module refcnt first.
  */
 i = -EAFNOSUPPORT;
 if (!try_module_get(net_families[family]->owner))
  goto out_release;

 if ((i = net_families[family]->create(sock, protocol)) < 0)
  goto out_module_put;
 /*
  * Now to bump the refcnt of the [loadable] module that owns this
  * socket at sock_release time we decrement its refcnt.
  */
 if (!try_module_get(sock->ops->owner)) {
  sock->ops = NULL;
  goto out_module_put;
 }
 /*
  * Now that we're done with the ->create function, the [loadable]
  * module can have its refcnt decremented
  */
 module_put(net_families[family]->owner);
 *res = sock;
 security_socket_post_create(sock, family, type, protocol, kern);

out:
 net_family_read_unlock();
 return i;
out_module_put:
 module_put(net_families[family]->owner);
out_release:
 sock_release(sock);
 goto out;
}

/*
 * Obtains the first available file descriptor and sets it up for use.
 * 取得第一个可用的描述符,并设置给它,它就是我们的返回值
 * This function creates file structure and maps it to fd space
 * of current process. On suclearcase/" target="_blank" >ccess it returns file descriptor
 * 为当前进程建立并映射文件描述符,成功返回描述符,值保存在sock->file中
 * and file struct implicitly stored in sock->file.
 * Note that another thread may close file descriptor before we return
 * from this function. We use the fact that now we do not refer
 * to socket after mapping. If one day we will need it, this
 * function will increment ref. count on file by 1.
 * 其他线程在函数返回之前可能关闭描述符,因此映射之后我们并不socket(靠,这是什么意思
 * 只建立并映射socket,但不是可用的?,日),在我们需要调用到描述符的时候
 * 对引用计数器加1
 * In any case returned fd MAY BE not valid!
 * 任何情况下返回文件描述符可能都是无效的
 * This race condition is unavoidable
 * with shared fd spaces, we cannot solve it inside kernel,
 * 这种竞争情况无可避免(指不同线程对文件描述符操作的竞争),在内核中这个问题不能解决
 * but we take care of internal coherence yet. //这个不好翻译
 */
 
int sock_map_fd(struct socket *sock)
{
 int fd;
 /*
   * "quick string" -- eases parameter passing, but more importantly
   * saves "metadata" about the string (ie length and the hash).
   *
   * hash comes first so it snuggles against d_parent and d_bucket in the
   * dentry.
   * struct qstr {
  * unsigned int hash;
  * const unsigned char *name;
  * unsigned int len;
  * };
   */
 struct qstr this;
 char name[32];

 /*
  * Find a file descriptor suitable for return to the user.
  */

 //取得第一个可用的文件描述符
 fd = get_unused_fd();
 if (fd >= 0) {//成功
  struct file *file = get_empty_filp();//取得一个可用的文件结构

  if (!file) {//没有取得
   put_unused_fd(fd); //释放文件描述符
   fd = -ENFILE;
   goto out;
  }

  sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
  this.name = name;
  this.len = strlen(name);
  this.hash = SOCK_INODE(sock)->i_ino;

  //日,这里又分配什么?
  file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
  if (!file->f_dentry) {//失败
   put_filp(file);
   put_unused_fd(fd);
   fd = -ENOMEM;
   goto out;
  }
  file->f_dentry->d_op = &sockfs_dentry_operations;
  d_add(file->f_dentry, SOCK_INODE(sock));
  file->f_vfsmnt = mntget(sock_mnt);//原语操作
  file->f_mapping = file->f_dentry->d_inode->i_mapping;

  sock->file = file;
  file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
  file->f_mode = FMODE_READ | FMODE_WRITE;
  file->f_flags = O_RDWR;
  file->f_pos = 0;
  fd_install(fd, file);//安装文件描述符
 }

out:
 return fd;
}

原文转自:http://www.ltesting.net