作者:gfree.wind@gmail.com
sock_sendmsg的代码很简单- int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
-
{
-
struct kiocb iocb;
-
struct sock_iocb siocb;
-
int ret;
-
-
init_sync_kiocb(&iocb, NULL);
-
iocb.private = &siocb;
-
ret = __sock_sendmsg(&iocb, sock, msg, size);
-
if (-EIOCBQUEUED == ret)
-
ret = wait_on_sync_kiocb(&iocb);
-
return ret;
-
}
首先定义了一个struct kiocb类型的iocb——linux内核中所有I/O操作都要依赖于合格结构,然后初始化它。然后调用__sock_sendmsg,而__sock_sendmsg又调用UDP的sendmsg去做真正的发送。
也就是说,对于UDP的socket来说,sendto调用,真正去做工作的是udp_sendmsg这个函数。
- int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
-
size_t len)
-
{
-
struct inet_sock *inet = inet_sk(sk);
-
struct udp_sock *up = udp_sk(sk);
-
int ulen = len;
-
struct ipcm_cookie ipc;
-
struct rtable *rt = NULL;
-
int free = 0;
-
int connected = 0;
-
__be32 daddr, faddr, saddr;
-
__be16 dport;
-
u8 tos;
-
int err, is_udplite = IS_UDPLITE(sk);
-
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
-
int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
将sk转为udp内部使用的类型指针,在TCP/IP中充斥了这样的转换。主要原因是因为对于上层来说,需要一个统一的类型,而到了底层的具体实现时,都会将上层抽象的数据类型,转为自己所需的类型。
并判断该UDP是否是udplite——udplite的定义见
- if (len > 0xFFFF)
-
return -EMSGSIZE;
-
-
/*
-
* Check the flags.
-
*/
-
-
if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */
-
return -EOPNOTSUPP;
进行一些错误检测。
- ipc.opt = NULL;
-
ipc.shtx.flags = 0;
-
-
if (up->pending) {
-
/*
-
* There are pending frames.
-
* The socket lock must be held while it's corked.
-
*/
-
lock_sock(sk);
-
if (likely(up->pending)) {
-
if (unlikely(up->pending != AF_INET)) {
-
release_sock(sk);
-
return -EINVAL;
-
}
-
goto do_append_data;
-
}
-
release_sock(sk);
-
}
-
ulen += sizeof(struct udphdr);
如果该socket有pending的frame,那么直接将数据追加。如果没有就ulen加上udp首部的长度。
- /*
-
* Get and verify the address.
-
*/
-
if (msg->msg_name) {
-
struct sockaddr_in * usin = (struct sockaddr_in *)msg->msg_name;
-
if (msg->msg_namelen < sizeof(*usin))
-
return -EINVAL;
-
if (usin->sin_family != AF_INET) {
-
if (usin->sin_family != AF_UNSPEC)
-
return -EAFNOSUPPORT;
-
}
-
-
daddr = usin->sin_addr.s_addr;
-
dport = usin->sin_port;
-
if (dport == 0)
-
return -EINVAL;
-
} else {
-
if (sk->sk_state != TCP_ESTABLISHED)
-
return -EDESTADDRREQ;
-
daddr = inet->inet_daddr;
-
dport = inet->inet_dport;
-
/* Open fast path for connected socket.
-
Route will not be used, if at least one option is set.
-
*/
-
connected = 1;
-
}
-
ipc.addr = inet->inet_saddr;
如果msg->msg_name不为空,就说明指定了目的地址,对其进行检验。如果为空,就就需要对sock的状态进行检验,查看其是否是连接状态——UDP的socket同样是可以调用connect,这样就不需要每次都指定发送地址了。
今天有点困了,就这样了。
阅读(494) | 评论(0) | 转发(0) |