本文主要介绍了getsockname()和getpeername()的内核实现。

内核版本:3.6

Author:zhangskd @ csdn blog

应用层

int getsockname(int s, struct sockaddr *name, socklen_t *namelen);

Get the current name for the specified socket.

获取本地套接口的名字,包括它的IP和端口。

int getpeername(int s, struct sockaddr *name, socklen_t *namelen);

Get the name of connected peer socket.

获取远程套接口的名字,包括它的IP和端口。

getsockname()在指定的套接口绑定地址和端口后才能调用,即服务器在bind()后可调用,

客户端在bind()或connect()之后可调用。getpeername()在连接建立之后才可调用。

系统调用

getsockname()和getpeername()是由glibc提供的,声明位于include/sys/socket.h中,实现位于

sysdeps/mach/hurd/getsockname.c和sysdeps/mach/hurd/getpeername.c中。它们主要是用于从用户空间

进入名为sys_socketcall的系统调用,并传递参数。sys_socketcall()实际上是所有socket函数进入内核空间

的共同入口。

在sys_socketcall()中会调用sys_getsockname()和sys_getpeername()。

SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
{
...
switch(call) {
case SYS_GETSOCKNAME:
err = sys_getsockname(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);
break; case SYS_GETPEERNAME:
err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);
break;
...
}
return err;
}

经过了Socket层的总入口sys_socketcall(),现在进入sys_getsockname()。

/* Get the local address ('name') of a socket object.
* Move the obtained name to user space.
*/
SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, int __user *, usockaddr_len)
{
struct socket *sock;
struct sockaddr_storage address;
int len, err, fput_needed; /* 通过文件描述符fd,找到对应的socket。
* 以fd为索引从当前进程的文件描述符表files_struct中找到对应的file实例,
* 然后从file实例的private_data成员中获取socket实例。
*/
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (! sock)
goto out; err = security_socket_getsockname(sock); /* SELinux相关 */
if (err)
goto out_put; /* SOCKET层的操作函数,如果是SOCK_STREAM,proto_ops为inet_stream_ops,
* 接下来调用inet_getname()。
*/
err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0);
if (err)
goto out_put; /* 把内核空间的socket地址复制到用户空间 */
err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); out_put:
fput_light(sock->file, fput_needed);
out:
return err;
}
static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen, void __user *uaddr, int __user *ulen)
{
int err;
int len; /* 把用户空间的地址长度保存到len */
err = get_user(len, ulen);
if (err)
return err; if (len > klen)
len = klen; if (len < 0 || len > sizeof(struct sockaddr_storage))
return -EINVAL; if (len) {
if (audit_sockaddr(klen, kaddr))
return -ENOMEM; if (copy_to_user(uaddr, kaddr, len)) /* 拷贝到用户空间 */
return -EFAULT;
} return __put_user(klen, ulen); /* 保存socket地址长度到用户空间 */
}

sys_getpeername()和sys_getsockname()差不多。

/* Get the remote address ('name') of a socket object.
* Move the obtained name to user space.
*/
SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, int __user *, usockaddr_len)
{
struct socket *sock;
struct sockaddr_storage address;
int len, err, fput_needed; /* 通过文件描述符fd,找到对应的socket。
* 以fd为索引从当前进程的文件描述符表files_struct中找到对应的file实例,
* 然后从file实例的private_data成员中获取socket实例。
*/
sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock != NULL) {
err = security_socket_getpeername(sock);
if (err) {
fput_light(sock->file, fput_needed);
return err;
} /* SOCKET层的操作函数,如果是SOCK_STREAM,proto_ops为inet_stream_ops,
* 接下来调用inet_getname()。
*/
err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 1); if (! err) /* 把内核空间的socket地址复制到用户空间 */
err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); fput_light(sock->file, fput_needed);
}
return err;
}

Socket层

SOCK_STREAM套接口的socket层操作函数集实例为inet_stream_ops。

getsockname()和getpeername()的socket层操作函数为inet_getname()。

const struct proto_ops inet_stream_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
...
.getname = inet_getname,
...
};

如果是getsockname(),则peer为0。是getpeername(),则peer为1。

/* This does both peername and sockname. */
int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
{
struct sock *sk = sock->sk;
struct inet_sock *inet = inet_sk(sk);
DECLARE_SOCKADDR(struct sockaddr_in *, sin, uaddr); sin->sin_family = AF_INET;
if (peer) { /* 如果是getpeername,要求连接已经建立 */
if (! inet->inet_dport || (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
peer == 1))
return -ENOTCONN; /* Transport endpoint is not connected */ sin->sin_port = inet->inet_dport; /* 获取对端端口 */
sin->sin_addr.s_addr = inet->inet_daddr; /* 获取对端IP */ } else {
__be32 addr = inet->inet_rcv_saddr;
if (! addr)
addr = inet->inet_saddr; sin->sin_port = inet->inet_sport; /* 获取本端端口 */
sin->sin_addr.s_addr = addr; /* 获取本端IP */
} memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
*uaddr_len = sizeof(*sin);
return 0;
} #define DECLARE_SOCKADDR(type, dst, src) \
type dst = ({ __sockaddr_check_size(sizeof(*dst)); (type) src; }) #define __sockaddr_check_size(size) \
BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage)))

Socket层实现系列 — getsockname()和getpeername()的实现的更多相关文章

  1. Socket层实现系列 — send()类发送函数的实现

    主要内容:socket发送函数的系统调用.Socket层实现. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 发送流程图 以下是send().sendt ...

  2. Socket层实现系列 — connect()的实现

    主要内容:connect()的Socket层实现.期间进程的睡眠和唤醒. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 应用层 int connect( ...

  3. Socket层实现系列 — 信号驱动的异步等待

    主要内容:Socket的异步通知机制. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 概述 socket上定义了几个IO事件:状态改变事件.有数据可读事 ...

  4. Socket层实现系列 — 睡眠驱动的同步等待

    主要内容:Socket的同步等待机制,connect和accept等待的实现. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 概述 socket上定义了 ...

  5. Socket层实现系列 — accept()的实现(一)

    本文主要介绍了accept()的系统调用.Socket层实现,以及TCP层实现. 内核版本:3.6 Author:zhangskd @ csdn blog 应用层 int accept(int soc ...

  6. Socket层实现系列 — listen()的实现

    本文主要分析listen()的内核实现,包括它的系统调用.Socket层实现.半连接队列,以及监听哈希表. 内核版本:3.6 Author:zhangskd @ csdn blog 应用层 int l ...

  7. Socket层实现系列 — bind()的实现(一)

    bind()函数的使用方法很简单,但是它是怎么实现的呢? 笔者从应用层出发,沿着网络协议栈,分析了bind()的系统调用.Socket层实现,以及它的TCP层实现. 本文主要内容:bind()的系统调 ...

  8. Socket层实现系列 — bind()的实现(二)

    本文主要内容:bind()的TCP层实现.端口的冲突处理,以及不同内核版本的实现差异. 内核版本:3.6 Author:zhangskd @ csdn blog TCP层实现 SOCK_STREAM套 ...

  9. Socket层实现系列 — I/O事件及其处理函数

    主要内容:Socket I/O事件的定义.I/O处理函数的实现. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd I/O事件定义 sock中定义了几个I/ ...

随机推荐

  1. 最优化方法:范数和规则化regularization

    http://blog.csdn.net/pipisorry/article/details/52108040 范数规则化 机器学习中出现的非常频繁的问题有:过拟合与规则化.先简单的来理解下常用的L0 ...

  2. Swift基础之守卫语句guard

    本篇文章翻译自:http://ericcerney.com/swift-guard-statement/原作者:ecerney该语法为swift2.0之后添加的新特性 最开始在Apple的Platfo ...

  3. Java学习之栈和堆的区别

    在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配. 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配 ...

  4. 剑指Offer——滴滴笔试题+知识点总结

    剑指Offer--滴滴笔试题+知识点总结 情景回顾 时间:2016.9.18 15:00-17:00 地点:山东省网络环境智能计算技术重点实验室 事件:滴滴笔试   总体来说,滴滴笔试内容体量不算多, ...

  5. 2.Cocos2d-x-3.2编写3d打飞机,项目代码总结

    1.AppDelete中applicationDidFinishLaunching代码示范 2.当电话来了时,停止恢复游戏声音的代码(在AppDelegate中加入下面代码) boolAppDel ...

  6. Dynamics CRM 后台通过组织服务获取时间字段值的准确转换

    做CRM开发的都知道,在系统时间字段的处理上是有讲究的,因为数据库中存的是UTC时间,CRM的界面时间字段会根据个人设置中的时区以及格式自动调整,这是最基本的一面,那还有很多使用时间的场景,比如脚本使 ...

  7. iOS中让Settings Bundle中的变化立即在App中反应出来的两种方法

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 为了能够在Settings Bundle中的变化在进入App后 ...

  8. C++对象模型的那些事儿之一:对象模型(上)

    前言 很早以前就听人推荐了<深入理解C++对象模型>这本书,从年初买来到现在也只是偶尔翻了翻,总觉得晦涩难懂,放在实验室上吃灰吃了好久.近期由于找工作对C++的知识做了一个全面系统的学习, ...

  9. 【Unity Shaders】Transparency —— 使用渲染队列进行深度排序

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  10. 使用Mediaplay类写一个播放器

    我们知道android本身播放视频的的能力是有限的..先来一个Demo 另附我的一个还未成熟的播放器,下载地址:http://www.eoemarket.com/soft/370334.html,正在 ...