读核日记socket篇
今天被一个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==NULL)
{
request_module("net-pf-%d",family);
}
#endif
net_family_read_lock();
if (net_families == 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->owner))
goto out_release;
if ((i = net_families->create(sock, protocol)) < 0)
goto out_module_put;
/*
* Now to bump the refcnt of the 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
* module can have its refcnt decremented
*/
module_put(net_families->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->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 success 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 th
e 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;
/*
* 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, "", 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;
}