天天看点

LwIP之套接字接口

/* 套接字结构体 */
struct lwip_sock 
{
  /* API连接指针 */
  struct netconn *conn;
  /* 前一次读剩下的数据 */
  void *lastdata;
  /* 前一次读数据的偏移量 */
  u16_t lastoffset;
  /* 接收数据的次数 */
  s16_t rcvevent;
  /* 发送成功的次数 */
  u16_t sendevent;
  /* 错误发生次数 */
  u16_t errevent; 
  /* 最近发生的错误 */
  int err;
  /* 所有select描述符个数 */
  int select_waiting;
};

/* select控制块 */
struct lwip_select_cb 
{
  /* 用于将所有控制块连接起来 */
  struct lwip_select_cb *next;
  struct lwip_select_cb *prev;
  /* 读描述符集合 */
  fd_set *readset;
  /* 写描述符集合 */
  fd_set *writeset;
  /* 异常描述符集合 */
  fd_set *exceptset;
  /* 触发事件设1 */
  int sem_signalled;
  /* 信号量 */
  sys_sem_t sem;
};

/* 套接字属性数据 */
struct lwip_setgetsockopt_data
{
	/* 所属套接字 */
  struct lwip_sock *sock;
  int level;					//层
  int optname;				//选项名字
  void *optval;				//数据
  socklen_t *optlen;	//数据长度
  err_t err;
};

/* 套接字数组 */
static struct lwip_sock sockets[NUM_SOCKETS];
/* select链表 */
static struct lwip_select_cb *select_cb_list;
/* 链表发生改变时就加一 */
static volatile int select_cb_ctr;

/* 错误类型 */
static const int err_to_errno_table[] = {
  0,             /* ERR_OK          0      No error, everything OK. */
  ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
  ENOBUFS,       /* 内存不足 */
  EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
  EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
  EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
  EINVAL,        /* 参数错误 */
  EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */
  EADDRINUSE,    /* ERR_USE        -8      Address in use.          */
  EALREADY,      /* ERR_ISCONN     -9      Already connected.       */
  ECONNABORTED,  /* ERR_ABRT       -10     Connection aborted.      */
  ECONNRESET,    /* ERR_RST        -11     Connection reset.        */
  ENOTCONN,      /* ERR_CLSD       -12     Connection closed.       */
  ENOTCONN,      /* ERR_CONN       -13     Not connected.           */
  EIO,           /* 内部错误 */
  -1,            /* ERR_IF         -15     Low-level netif error    */
};

#define ERR_TO_ERRNO_TABLE_SIZE \
  (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))

#define err_to_errno(err) \
  ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
    err_to_errno_table[-(err)] : EIO)

#define set_errno(err)

/* 套接字设置错误 */
#define sock_set_errno(sk, e) do { \
  sk->err = (e); \
  set_errno(sk->err); \
} while (0)

static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
static void lwip_getsockopt_internal(void *arg);
static void lwip_setsockopt_internal(void *arg);

/* socket编程初始化 */
void lwip_socket_init(void)
{
}

/* 根据套接字描述符获取套接字结构体指针 */
static struct lwip_sock *get_socket(int s)
{
  struct lwip_sock *sock;

  if((s < 0) || (s >= NUM_SOCKETS)) 
  {
    set_errno(EBADF);
    return NULL;
  }

  sock = &sockets[s];

  if(!sock->conn) 
  {
    set_errno(EBADF);
    return NULL;
  }

  return sock;
}

/* 通过套接字描述符获取套接字 */
static struct lwip_sock *tryget_socket(int s)
{
  if((s < 0) || (s >= NUM_SOCKETS)) 
  {
    return NULL;
  }
	
  if(!sockets[s].conn) 
  {
    return NULL;
  }

  return &sockets[s];
}

/* 创建套接字描述符 */
static int alloc_socket(struct netconn *newconn, int accepted)
{
  int i;

  /* 找一个空的套接字描述符 */
  for(i = 0; i < NUM_SOCKETS; ++i) 
  {
    if(!sockets[i].conn) 
	{
	  /* 初始化所有参数 */
      sockets[i].conn = newconn;
      SYS_ARCH_UNPROTECT(lev);
      sockets[i].lastdata = NULL;
      sockets[i].lastoffset = 0;
      sockets[i].rcvevent = 0;
      sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
      sockets[i].errevent = 0;
      sockets[i].err = 0;
      sockets[i].select_waiting = 0;

      return i;
    }
  }

  return -1;
}

/* 释放套接字 */
static void free_socket(struct lwip_sock *sock, int is_tcp)
{
  void *lastdata;

  lastdata = sock->lastdata;
  sock->lastdata = NULL;
  sock->lastoffset = 0;
  sock->err = 0;

  sock->conn = NULL;

  /* 释放已经收到未取用的数据 */
  if(lastdata != NULL) 
  {
    if(is_tcp) 
	{
      pbuf_free((struct pbuf *)lastdata);
    } 
	else 
	{
      netbuf_delete((struct netbuf *)lastdata);
    }
  }
}

/* 接受连接 */
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
  struct lwip_sock *sock, *nsock;
  struct netconn *newconn;
  ip_addr_t naddr;
  u16_t port;
  int newsock;
  struct sockaddr_in sin;
  err_t err;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  /* 非阻塞,并且没有连接事件,返回错误 */
  if(netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) 
  {
    sock_set_errno(sock, EWOULDBLOCK);
    return -1;
  }

  /* 接受连接 */
  err = netconn_accept(sock->conn, &newconn);
  if(err != ERR_OK) 
  {
    if(netconn_type(sock->conn) != NETCONN_TCP) 
	{
      sock_set_errno(sock, EOPNOTSUPP);
      return EOPNOTSUPP;
    }
    sock_set_errno(sock, err_to_errno(err));
    return -1;
  }

  /* 设置不自动接收数据 */
  netconn_set_noautorecved(newconn, 1);

  /* 获取本地IP和端口号 */
  err = netconn_peer(newconn, &naddr, &port);
  if(err != ERR_OK) 
  {
    netconn_delete(newconn);
    sock_set_errno(sock, err_to_errno(err));
    return -1;
  }

  /* 填充sockaddr_in结构体 */
  if(NULL != addr) 
  {
    memset(&sin, 0, sizeof(sin));
    sin.sin_len = sizeof(sin);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
    if(*addrlen > sizeof(sin))
      *addrlen = sizeof(sin);

    MEMCPY(addr, &sin, *addrlen);
  }

  /* 为新连接创建新的套接字描述符 */
  newsock = alloc_socket(newconn, 1);
  if(newsock == -1) 
  {
    netconn_delete(newconn);
    sock_set_errno(sock, ENFILE);
    return -1;
  }

  nsock = &sockets[newsock];

  nsock->rcvevent += (s16_t)(-1 - newconn->socket);
  newconn->socket = newsock;

  sock_set_errno(sock, 0);
	
  /* 返回套接字描述符 */
  return newsock;
}

/* 绑定本地端口 */
int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{
  struct lwip_sock *sock;
  ip_addr_t local_addr;
  u16_t local_port;
  err_t err;
  const struct sockaddr_in *name_in;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }
  
  /* 类型转换 */
  name_in = (const struct sockaddr_in *)(void *)name;

  /* 取出IP地址和端口号 */
  inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
  local_port = name_in->sin_port;

  /* 绑定本地端口 */
  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
  if(err != ERR_OK) 
  {
    sock_set_errno(sock, err_to_errno(err));
    return -1;
  }

  sock_set_errno(sock, 0);
  return 0;
}

/* 关闭套接字 */
int lwip_close(int s)
{
  struct lwip_sock *sock;
  int is_tcp = 0;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  if(sock->conn != NULL) 
  {
    is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
  } 

  /* 删除连接 */
  netconn_delete(sock->conn);

  /* 释放套接字 */
  free_socket(sock, is_tcp);

  set_errno(0);
	
  return 0;
}

/* 连接远程端口 */
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
{
  struct lwip_sock *sock;
  err_t err;
  const struct sockaddr_in *name_in;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  /* 类型转换 */
  name_in = (const struct sockaddr_in *)(void*)name;

  if(name_in->sin_family == AF_UNSPEC) 
  {
    err = netconn_disconnect(sock->conn);
  } 
  else 
  {
    ip_addr_t remote_addr;
    u16_t remote_port;

	/* 取出IP和端口号 */
    inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
    remote_port = name_in->sin_port;

	/* 连接远程端口 */
    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
  }

  if(err != ERR_OK) 
  {
    sock_set_errno(sock, err_to_errno(err));
    return -1;
  }

  sock_set_errno(sock, 0);

  return 0;
}

/* 侦听 */
int lwip_listen(int s, int backlog)
{
  struct lwip_sock *sock;
  err_t err;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  /* 监听队列最大数 */
  backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);

  /* 开始侦听 */
  err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
  if(err != ERR_OK) 
  {
    if(netconn_type(sock->conn) != NETCONN_TCP) 
	{
      sock_set_errno(sock, EOPNOTSUPP);
      return EOPNOTSUPP;
    }
    sock_set_errno(sock, err_to_errno(err));
		
    return -1;
  }

  sock_set_errno(sock, 0);
  return 0;
}

/* 接收数据(可选非阻塞/数据接收后不删除,返回远程IP和端口号) */
int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
{
  struct lwip_sock *sock;
  void *buf = NULL;
  struct pbuf *p;
  u16_t buflen, copylen;
  int off = 0;
  ip_addr_t *addr;
  u16_t port;
  u8_t done = 0;
  err_t err;
  
  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  do 
  {
	/* 前一次读剩下数据 */
	if(sock->lastdata) 
	{
      buf = sock->lastdata;
    }
	/* 前一次没有读剩下数据 */
	else 
	{
	  /* 非阻塞态,且没有数据 */
      if(((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && (sock->rcvevent <= 0)) 
	  {
        if(off > 0) 
		{
          netconn_recved(sock->conn, (u32_t)off);
          sock_set_errno(sock, 0);
					
          return off;
        }
        sock_set_errno(sock, EWOULDBLOCK);
				
        return -1;
      }

	  /* 接收数据 */
      if(netconn_type(sock->conn) == NETCONN_TCP) 
	  {
        err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
      } 
	  else 
	  {
        err = netconn_recv(sock->conn, (struct netbuf **)&buf);
      }

	  /* 更新接收窗口 */
      if(err != ERR_OK) 
	  {
        if(off > 0) 
		{
          netconn_recved(sock->conn, (u32_t)off);
          sock_set_errno(sock, 0);
          return off;
        }

        sock_set_errno(sock, err_to_errno(err));
        if(err == ERR_CLSD) 
		{
          return 0;
        } 
		else 
		{
          return -1;
        }
      }
      sock->lastdata = buf;
    }

	/* 取出数据pbuf */
    if(netconn_type(sock->conn) == NETCONN_TCP) 
	{
      p = (struct pbuf *)buf;
    } 
	else 
	{
      p = ((struct netbuf *)buf)->p;
    }
		
	/* 数据长度 */
    buflen = p->tot_len;
    buflen -= sock->lastoffset;

    if(len > buflen) 
	{
      copylen = buflen;
    } 
	else
	{
      copylen = (u16_t)len;
    }

	/* 将数据拷贝出来 */
    pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);

    off += copylen;

	/* 数据是否读完 */
    if(netconn_type(sock->conn) == NETCONN_TCP) 
	{
      len -= copylen;
      if((len <= 0) || (p->flags & PBUF_FLAG_PUSH) || (sock->rcvevent <= 0) || ((flags & MSG_PEEK) != 0)) 
	  {
        done = 1;
      }
    } 
	else 
	{
      done = 1;
    }

	/* 数据读完 */
    if(done) 
	{
      ip_addr_t fromaddr;
      if(from && fromlen) 
	  {
        struct sockaddr_in sin;

		/* 获取远程IP和端口号 */
        if(netconn_type(sock->conn) == NETCONN_TCP) 
		{
          addr = &fromaddr;
          netconn_getaddr(sock->conn, addr, &port, 0);
        } 
		else 
		{
          addr = netbuf_fromaddr((struct netbuf *)buf);
          port = netbuf_fromport((struct netbuf *)buf);
        }

        memset(&sin, 0, sizeof(sin));
        sin.sin_len = sizeof(sin);
        sin.sin_family = AF_INET;
        sin.sin_port = htons(port);
        inet_addr_from_ipaddr(&sin.sin_addr, addr);

        if(*fromlen > sizeof(sin)) 
		{
          *fromlen = sizeof(sin);
        }

        MEMCPY(from, &sin, *fromlen);
      } 
    }

	/* 释放已经读取的数据 */
    if((flags & MSG_PEEK) == 0) 
	{
      if((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) 
	  {
        sock->lastdata = buf;
        sock->lastoffset += copylen;
      } 
	  else 
	  {
        sock->lastdata = NULL;
        sock->lastoffset = 0;
        if(netconn_type(sock->conn) == NETCONN_TCP) 
		{
          pbuf_free((struct pbuf *)buf);
        } 
		else 
		{
          netbuf_delete((struct netbuf *)buf);
        }
      }
    }
  }while(!done);

  /* 更新接收窗口 */
  if(off > 0) 
  {
    netconn_recved(sock->conn, (u32_t)off);
  }
  sock_set_errno(sock, 0);

  return off;
}

/* 接收数据 */
int lwip_read(int s, void *mem, size_t len)
{
  return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
}

/* 接收数据 */
int lwip_recv(int s, void *mem, size_t len, int flags)
{
  return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
}

/* 发送数据(用于已经绑定远程IP和端口号) */
int lwip_send(int s, const void *data, size_t size, int flags)
{
  struct lwip_sock *sock;
  err_t err;
  u8_t write_flags;
  size_t written;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  /* 发送非TCP数据 */
  if(sock->conn->type != NETCONN_TCP) 
  {
    return lwip_sendto(s, data, size, flags, NULL, 0);
  }

  /* TCP发送数据 */
  write_flags = NETCONN_COPY | ((flags & MSG_MORE) ? NETCONN_MORE : 0) | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
  written = 0;
  err = netconn_write_partly(sock->conn, data, size, write_flags, &written);

  sock_set_errno(sock, err_to_errno(err));
  return (err == ERR_OK ? (int)written : -1);
}

/* 发送数据(用于未绑定远程IP和端口号) */
int lwip_sendto(int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
{
  struct lwip_sock *sock;
  err_t err;
  u16_t short_size;
  const struct sockaddr_in *to_in;
  u16_t remote_port;
  struct netbuf buf;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  /* TCP发送数据 */
  if(sock->conn->type == NETCONN_TCP) 
  {
    return lwip_send(s, data, size, flags);
  }

  short_size = (u16_t)size;
  to_in = (const struct sockaddr_in *)(void*)to;
  buf.p = buf.ptr = NULL;

  /* 设置netbuf远程IP和端口号 */
  if(to) 
  {
    inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
    remote_port = ntohs(to_in->sin_port);
    netbuf_fromport(&buf) = remote_port;
  } 
  else 
  {
    remote_port = 0;
    ip_addr_set_any(&buf.addr);
    netbuf_fromport(&buf) = 0;
  }

  /* 为netbuf申请PBUF_REF型pbuf内存,指向已存在RAM */
  err = netbuf_ref(&buf, data, short_size);
  /* UDP或RAW发送数据 */
  if(err == ERR_OK) 
  {
    err = netconn_send(sock->conn, &buf);
  }

  /* 释放netbuf */
  netbuf_free(&buf);

  sock_set_errno(sock, err_to_errno(err));

  return (err == ERR_OK ? short_size : -1);
}

/* 创建套接字 */
int lwip_socket(int domain, int type, int protocol)
{
  struct netconn *conn;
  int i;

  /* 判断套接字类型 */
  switch(type) 
  {
	/* 原始套接字 */
	case SOCK_RAW:
	  /* 创建一个原始IP连接并且设置回调函数 */
	  conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
	  break;

	/* 数据报套接字 */
	case SOCK_DGRAM:
	  /* 创建一个UDP连接结构体并且设置回调函数 */
	  conn = netconn_new_with_callback((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP, event_callback);
	  break;

	/* 流式套接字 */
	case SOCK_STREAM:
	  /* 创建一个TCP连接结构体并且设置回调函数 */
	  conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
	  if(conn != NULL) 
	  {
		/* 设置不自动接收数据 */
		netconn_set_noautorecved(conn, 1);
	  }
	  break;

	default:
	  set_errno(EINVAL);
	  return -1;
  }

  if(!conn) 
  {
    set_errno(ENOBUFS);
    return -1;
  }

  /* 创建套接字描述符 */
  i = alloc_socket(conn, 0);
  /* 失败 */
  if(i == -1) 
  {
	/* 删除连接 */
    netconn_delete(conn);
    set_errno(ENFILE);
    return -1;
  }

  /* 套接字描述符 */
  conn->socket = i;
  set_errno(0);

  return i;
}

/* 发送数据(用于已经绑定远程IP和端口号) */
int lwip_write(int s, const void *data, size_t size)
{
  return lwip_send(s, data, size, 0);
}

/* 扫描读写错误集合有没有事件发生 */
static int lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
{
  int i, nready = 0;
  fd_set lreadset, lwriteset, lexceptset;
  struct lwip_sock *sock;

  /* 清空所有集合 */
  FD_ZERO(&lreadset);
  FD_ZERO(&lwriteset);
  FD_ZERO(&lexceptset);

  /* 检查所有描述符 */
  for(i = 0; i < maxfdp1; i++) 
  {
    void* lastdata = NULL;
    s16_t rcvevent = 0;
    u16_t sendevent = 0;
    u16_t errevent = 0;

	/* 通过套接字描述符获取套接字 */
    sock = tryget_socket(i);
	/* 获取套接字已经发生的事件数 */
    if(sock != NULL) 
	{
      lastdata = sock->lastdata;
      rcvevent = sock->rcvevent;
      sendevent = sock->sendevent;
      errevent = sock->errevent;
    }

	/* 该描述符发生读事件且属于读集合 */
    if(readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) 
	{
	  /* 设置读事件 */
      FD_SET(i, &lreadset);
      nready++;
    }

	/* 该描述符发生写事件且属于写集合 */
    if(writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) 
	{
	  /* 设置写事件 */
      FD_SET(i, &lwriteset);
      nready++;
    }

	/* 该描述符发生异常事件且属于异常集合 */
    if(exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) 
	{
	  /* 设置异常事件 */
      FD_SET(i, &lexceptset);
      nready++;
    }
  }

  /* 返回读写异常事件集合 */
  *readset_out = lreadset;
  *writeset_out = lwriteset;
  *exceptset_out = lexceptset;

  return nready;
}

/* 多路复用 */
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout)
{
  u32_t waitres = 0;
  int nready;
  fd_set lreadset, lwriteset, lexceptset;
  u32_t msectimeout;
  struct lwip_select_cb select_cb;
  err_t err;
  int i;

  /* 扫描读写错误集合有没有事件发生 */
  nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);

  /* 没有事件发生 */
  if(!nready) 
  {
	/* 阻塞时间0 */
    if(timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) 
	{
      goto return_copy_fdsets;
    }

    /* 创建select信号 */
    select_cb.next = NULL;
    select_cb.prev = NULL;
    select_cb.readset = readset;
    select_cb.writeset = writeset;
    select_cb.exceptset = exceptset;
    select_cb.sem_signalled = 0;
    err = sys_sem_new(&select_cb.sem, 0);
    if(err != ERR_OK) 
	{
      set_errno(ENOMEM);
      return -1;
    }

    /* 插入select链表 */
    select_cb.next = select_cb_list;
    if(select_cb_list != NULL) 
	{
      select_cb_list->prev = &select_cb;
    }
    select_cb_list = &select_cb;
    
    select_cb_ctr++;

    /* 统计需要select描述符个数 */
    for(i = 0; i < maxfdp1; i++) 
	{
      if((readset && FD_ISSET(i, readset)) ||
         (writeset && FD_ISSET(i, writeset)) ||
         (exceptset && FD_ISSET(i, exceptset))) 
	  {
        struct lwip_sock *sock = tryget_socket(i);
        sock->select_waiting++;
      }
    }

    /* 扫描读写错误集合有没有事件发生 */
    nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
    /* 没有事件发生 */
	if(!nready) 
	{
	  /* 永远阻塞 */
      if(timeout == 0) 
	  {
        msectimeout = 0;
      } 
	  /* 阻塞时间 */
	  else 
	  {
        msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000));
        if(msectimeout == 0) 
		{
          msectimeout = 1;
        }
      }

	  /* 等待事件发生 */
      waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
    }
		
	/* 检查是否有改变 */
    for(i = 0; i < maxfdp1; i++) 
	{
      if((readset && FD_ISSET(i, readset)) ||
         (writeset && FD_ISSET(i, writeset)) ||
         (exceptset && FD_ISSET(i, exceptset))) 
	  {
        struct lwip_sock *sock = tryget_socket(i);
        sock->select_waiting--;
      }
    }

	/* 将select控制块从链表删除 */
    if(select_cb.next != NULL) 
	{
      select_cb.next->prev = select_cb.prev;
    }
    if(select_cb_list == &select_cb) 
	{
      select_cb_list = select_cb.next;
    } 
	else 
	{
      select_cb.prev->next = select_cb.next;
    }
    select_cb_ctr++;
 
	/* 释放信号量 */
    sys_sem_free(&select_cb.sem);
	/* 超时 */
    if(waitres == SYS_ARCH_TIMEOUT)  
	{
      goto return_copy_fdsets;
    }

    /* 扫描读写错误集合有没有事件发生 */
    nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
  }

return_copy_fdsets:
  set_errno(0);
	
	/* 返回发生事件集合 */
  if(readset) 
  {
    *readset = lreadset;
  }
  if(writeset) 
  {
    *writeset = lwriteset;
  }
  if(exceptset) 
  {
    *exceptset = lexceptset;
  }

  return nready;
}

/* 套接字回调函数 */
static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
{
  int s;
  struct lwip_sock *sock;
  struct lwip_select_cb *scb;
  int last_select_cb_ctr;

  if(conn) 
  {
    s = conn->socket;
    if(s < 0) 
	{
      if(conn->socket < 0) 
	  {
        if(evt == NETCONN_EVT_RCVPLUS) 
		{
          conn->socket--;
        }
        return;
      }
      s = conn->socket;
    }

	/* 根据套接字描述符获取套接字结构体指针 */
    sock = get_socket(s);
    if(!sock) 
	{
      return;
    }
  } 
  else 
  {
    return;
  }

  /* 事件处理 */
  switch(evt) 
  {
    case NETCONN_EVT_RCVPLUS:
      sock->rcvevent++;
      break;
    case NETCONN_EVT_RCVMINUS:
      sock->rcvevent--;
      break;
    case NETCONN_EVT_SENDPLUS:
      sock->sendevent = 1;
      break;
    case NETCONN_EVT_SENDMINUS:
      sock->sendevent = 0;
      break;
    case NETCONN_EVT_ERROR:
      sock->errevent = 1;
      break;
    default:
      break;
  }

  if(sock->select_waiting == 0) 
  {
    return;
  }

again:
  /* 检查是否存在select事件 */
  for(scb = select_cb_list; scb != NULL; scb = scb->next) 
  {
    if(scb->sem_signalled == 0) 
	{
      int do_signal = 0;
      if(sock->rcvevent > 0)
	  {
        if(scb->readset && FD_ISSET(s, scb->readset)) 
		{
          do_signal = 1;
        }
      }
      if(sock->sendevent != 0) 
	  {
        if(!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) 
		{
          do_signal = 1;
        }
      }
      if(sock->errevent != 0) 
	  {
        if(!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) 
		{
          do_signal = 1;
        }
      }
			
	  /* 存在则解除阻塞 */
      if(do_signal) 
	  {
        scb->sem_signalled = 1;
        sys_sem_signal(&scb->sem);
      }
    }
    last_select_cb_ctr = select_cb_ctr;
    if(last_select_cb_ctr != select_cb_ctr) 
	{
      goto again;
    }
  }
}

/* 关闭套接字连接方向 */
int lwip_shutdown(int s, int how)
{
  struct lwip_sock *sock;
  err_t err;
  u8_t shut_rx = 0, shut_tx = 0;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  if(sock->conn != NULL) 
  {
    if(netconn_type(sock->conn) != NETCONN_TCP) 
	{
      sock_set_errno(sock, EOPNOTSUPP);
      return EOPNOTSUPP;
    }
  } 
  else 
  {
    sock_set_errno(sock, ENOTCONN);
    return ENOTCONN;
  }

	/* 关闭连接方向 */
  if(how == SHUT_RD) 
  {
    shut_rx = 1;
  } 
  else if(how == SHUT_WR) 
  {
    shut_tx = 1;
  } 
  else if(how == SHUT_RDWR) 
  {
    shut_rx = 1;
    shut_tx = 1;
  } 
  else 
  {
    sock_set_errno(sock, EINVAL);
    return EINVAL;
  }
  err = netconn_shutdown(sock->conn, shut_rx, shut_tx);

  sock_set_errno(sock, err_to_errno(err));
  return (err == ERR_OK ? 0 : -1);
}

/* 获取本地或者远程IP和端口号 */
static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
{
  struct lwip_sock *sock;
  struct sockaddr_in sin;
  ip_addr_t naddr;

  /* 根据套接字描述符获取套接字结构体指针 */
  sock = get_socket(s);
  if(!sock) 
  {
    return -1;
  }

  /* 获取本地或者远程IP和端口号 */
  memset(&sin, 0, sizeof(sin));
  sin.sin_len = sizeof(sin);
  sin.sin_family = AF_INET;

  netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);

  sin.sin_port = htons(sin.sin_port);
  inet_addr_from_ipaddr(&sin.sin_addr, &naddr);

  if(*namelen > sizeof(sin)) 
	{
    *namelen = sizeof(sin);
  }

  MEMCPY(name, &sin, *namelen);
  sock_set_errno(sock, 0);
  return 0;
}

/* 获取远程IP和端口号 */
int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
{
  return lwip_getaddrname(s, name, namelen, 0);
}

/* 获取本地IP和端口号 */
int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
{
  return lwip_getaddrname(s, name, namelen, 1);
}

/* 获取套接字属性 */
int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
{
  err_t err = ERR_OK;
  struct lwip_sock *sock = get_socket(s);
  struct lwip_setgetsockopt_data data;

  if(!sock) 
  {
    return -1;
  }

  if((NULL == optval) || (NULL == optlen)) 
  {
    sock_set_errno(sock, EFAULT);
    return -1;
  }

  /* 判断参数合不合理 */
  switch(level) 
  {
	/* 套接字层 */
	case SOL_SOCKET:
	  /* 选项名 */
	  switch (optname) 
	  {
		case SO_ACCEPTCONN:
		case SO_BROADCAST:
		/* UNIMPL case SO_DEBUG: */
		/* UNIMPL case SO_DONTROUTE: */
		case SO_ERROR:
		case SO_KEEPALIVE:
		/* UNIMPL case SO_CONTIMEO: */
		/* UNIMPL case SO_OOBINLINE: */
		/* UNIMPL case SO_SNDBUF: */
		/* UNIMPL case SO_RCVLOWAT: */
		/* UNIMPL case SO_SNDLOWAT: */
		case SO_TYPE:
		/* UNIMPL case SO_USELOOPBACK: */
		  if(*optlen < sizeof(int)) 
		  {
		    err = EINVAL;
		  }
		  break;

		case SO_NO_CHECK:
		  if(*optlen < sizeof(int)) 
		  {
		    err = EINVAL;
		  }
		  if((sock->conn->type != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) 
		  {
			err = EAFNOSUPPORT;
		  }
		  break;

		default:
		  err = ENOPROTOOPT;
	  }
	  break;
                     
	  /* IP层 */
	  case IPPROTO_IP:
		switch(optname) 
		{
		  /* UNIMPL case IP_HDRINCL: */
		  /* UNIMPL case IP_RCVDSTADDR: */
		  /* UNIMPL case IP_RCVIF: */
		  case IP_TTL:
		  case IP_TOS:
			if(*optlen < sizeof(int)) 
			{
			  err = EINVAL;
			}
			break;

		  default:
			err = ENOPROTOOPT;
		}
		break;
         
	  /* TCP层 */
	  case IPPROTO_TCP:
	    if(*optlen < sizeof(int)) 
		{
		  err = EINVAL;
		  break;
		}
    
		if(sock->conn->type != NETCONN_TCP)
		  return 0;

			/* 选项名 */
			switch(optname) 
			{
				case TCP_NODELAY:
				case TCP_KEEPALIVE:
				break;
       
				default:
					err = ENOPROTOOPT;
			}
			break;

		/* Level: IPPROTO_UDPLITE */
		case IPPROTO_UDPLITE:
			if(*optlen < sizeof(int)) 
			{
				err = EINVAL;
				break;
			}
	
			if(sock->conn->type != NETCONN_UDPLITE) 
			{
				return 0;
			}

			switch(optname) 
			{
				case UDPLITE_SEND_CSCOV:
				case UDPLITE_RECV_CSCOV:
					break;
		 
				default:
					err = ENOPROTOOPT;
			}
			break;

		/* UNDEFINED LEVEL */
		default:
			err = ENOPROTOOPT;
	}

   
	if(err != ERR_OK) 
	{
		sock_set_errno(sock, err);
		return -1;
	}

	/* 通知内核调用lwip_getsockopt_internal函数来处理套接字选项 */
  data.sock = sock;
  data.level = level;
  data.optname = optname;
  data.optval = optval;
  data.optlen = optlen;
  data.err = err;
  tcpip_callback(lwip_getsockopt_internal, &data);
  sys_arch_sem_wait(&sock->conn->op_completed, 0);
  err = data.err;

  sock_set_errno(sock, err);

  return err ? -1 : 0;
}

/* 获取套接字选项 */
static void lwip_getsockopt_internal(void *arg)
{
  struct lwip_sock *sock;
  int level, optname;
  void *optval;
  struct lwip_setgetsockopt_data *data;

  data = (struct lwip_setgetsockopt_data *)arg;
  sock = data->sock;
  level = data->level;
  optname = data->optname;
  optval = data->optval;

  switch(level) 
	{
		/* 套接字层 */
		case SOL_SOCKET:
			switch(optname) 
			{
				case SO_ACCEPTCONN:
				case SO_BROADCAST:
				/* UNIMPL case SO_DEBUG: */
				/* UNIMPL case SO_DONTROUTE: */
				case SO_KEEPALIVE:
				/* UNIMPL case SO_OOBINCLUDE: */
			    /*case SO_USELOOPBACK: UNIMPL */
					*(int *)optval = ip_get_option(sock->conn->pcb.ip, optname);
					break;

				case SO_TYPE:
					switch(NETCONNTYPE_GROUP(sock->conn->type)) 
					{
						case NETCONN_RAW:
							*(int*)optval = SOCK_RAW;
							break;
						case NETCONN_TCP:
							*(int*)optval = SOCK_STREAM;
							break;
						case NETCONN_UDP:
							*(int*)optval = SOCK_DGRAM;
							break;
						default:
							*(int*)optval = sock->conn->type;
					}
					break;

				case SO_ERROR:
					if((sock->err == 0) || (sock->err == EINPROGRESS)) 
					{
						sock_set_errno(sock, err_to_errno(sock->conn->last_err));
					} 
					*(int *)optval = sock->err;
					sock->err = 0;
					break;

				case SO_NO_CHECK:
					*(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
					break;
				default:
					break;
			}
			break;

		/* Level: IPPROTO_IP */
		case IPPROTO_IP:
			switch(optname) 
			{
				case IP_TTL:
					*(int*)optval = sock->conn->pcb.ip->ttl;
					break;
				case IP_TOS:
					*(int*)optval = sock->conn->pcb.ip->tos;
					break;

				default:
					break;
			}
			break;

		case IPPROTO_TCP:
			switch(optname) 
			{
				case TCP_NODELAY:
					*(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
					break;
				case TCP_KEEPALIVE:
					*(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
					break;

				default:
					LWIP_ASSERT("unhandled optname", 0);
					break;
			}
			break;

		case IPPROTO_UDPLITE:
			switch(optname) 
			{
				case UDPLITE_SEND_CSCOV:
					*(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
					break;
				case UDPLITE_RECV_CSCOV:
					*(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
					break;
				default:
					break;
			}
			break;

		default:
			break;
  }

  sys_sem_signal(&sock->conn->op_completed);
}

/* 设置套接字属性 */
int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
{
  struct lwip_sock *sock = get_socket(s);
  err_t err = ERR_OK;
  struct lwip_setgetsockopt_data data;

  if(!sock) 
	{
    return -1;
  }

  if(NULL == optval) 
	{
    sock_set_errno(sock, EFAULT);
    return -1;
  }

  /* 判断参数合不合理 */
  switch(level) 
	{
/* Level: SOL_SOCKET */
  case SOL_SOCKET:
    switch (optname) 
		{
    case SO_BROADCAST:
    /* UNIMPL case SO_DEBUG: */
    /* UNIMPL case SO_DONTROUTE: */
    case SO_KEEPALIVE:
    /* UNIMPL case case SO_CONTIMEO: */
    /* UNIMPL case SO_OOBINLINE: */
    /* UNIMPL case SO_SNDBUF: */
    /* UNIMPL case SO_RCVLOWAT: */
    /* UNIMPL case SO_SNDLOWAT: */
    /* UNIMPL case SO_USELOOPBACK: */
      if(optlen < sizeof(int)) 
			{
        err = EINVAL;
      }
      break;
    case SO_NO_CHECK:
      if(optlen < sizeof(int)) 
			{
        err = EINVAL;
      }

      if((sock->conn->type != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) 
			{
        err = EAFNOSUPPORT;
      }
      break;
    default:
      err = ENOPROTOOPT;
    }
    break;

/* Level: IPPROTO_IP */
  case IPPROTO_IP:
    switch(optname) 
		{
    /* UNIMPL case IP_HDRINCL: */
    /* UNIMPL case IP_RCVDSTADDR: */
    /* UNIMPL case IP_RCVIF: */
    case IP_TTL:
    case IP_TOS:
      if(optlen < sizeof(int)) 
			{
        err = EINVAL;
      }
      break;

      default:
        err = ENOPROTOOPT;
    }
    break;

/* Level: IPPROTO_TCP */
  case IPPROTO_TCP:
    if(optlen < sizeof(int)) 
		{
      err = EINVAL;
      break;
    }

    if(sock->conn->type != NETCONN_TCP)
      return 0;

    switch(optname) 
		{
    case TCP_NODELAY:
    case TCP_KEEPALIVE:
      break;

    default:
      err = ENOPROTOOPT;
    }
    break;

/* Level: IPPROTO_UDPLITE */
  case IPPROTO_UDPLITE:
    if(optlen < sizeof(int)) 
		{
      err = EINVAL;
      break;
    }

    if(sock->conn->type != NETCONN_UDPLITE)
      return 0;

    switch(optname) 
		{
    case UDPLITE_SEND_CSCOV:
    case UDPLITE_RECV_CSCOV:
      break;

    default:
      err = ENOPROTOOPT;
    }
    break;

/* UNDEFINED LEVEL */
  default:
    err = ENOPROTOOPT;
  }

  if(err != ERR_OK) 
	{
    sock_set_errno(sock, err);
    return -1;
  }

	/* 通知内核调用lwip_setsockopt_internal函数来处理套接字选项 */
  data.sock = sock;
  data.level = level;
  data.optname = optname;
  data.optval = (void*)optval;
  data.optlen = &optlen;
  data.err = err;
  tcpip_callback(lwip_setsockopt_internal, &data);
  sys_arch_sem_wait(&sock->conn->op_completed, 0);
  err = data.err;

  sock_set_errno(sock, err);
  return err ? -1 : 0;
}

/* 设置套接字选项 */
static void lwip_setsockopt_internal(void *arg)
{
  struct lwip_sock *sock;
  int level, optname;
  const void *optval;
  struct lwip_setgetsockopt_data *data;

  data = (struct lwip_setgetsockopt_data*)arg;
  sock = data->sock;
  level = data->level;
  optname = data->optname;
  optval = data->optval;

  switch(level) 
  {
/* Level: SOL_SOCKET */
  case SOL_SOCKET:
    switch(optname) 
	{
      /* The option flags */
      case SO_BROADCAST:
      /* UNIMPL case SO_DEBUG: */
      /* UNIMPL case SO_DONTROUTE: */
      case SO_KEEPALIVE:
      /* UNIMPL case SO_OOBINCLUDE: */
      /* UNIMPL case SO_USELOOPBACK: */
        if(*(int*)optval) 
		{
          ip_set_option(sock->conn->pcb.ip, optname);
        } 
		else 
		{
          ip_reset_option(sock->conn->pcb.ip, optname);
        }
        break;

      case SO_NO_CHECK:
        if(*(int*)optval) 
		{
          udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
        } 
		else 
		{
          udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
        }
        break;

      default:
        break;
    }  /* switch (optname) */
    break;

/* Level: IPPROTO_IP */
  case IPPROTO_IP:
    switch(optname) 
	{
    case IP_TTL:
      sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", s, sock->conn->pcb.ip->ttl));
      break;
    case IP_TOS:
      sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", s, sock->conn->pcb.ip->tos));
      break;

    default:
      break;
    }
    break;

/* Level: IPPROTO_TCP */
  case IPPROTO_TCP:
    switch(optname) 
	{
    case TCP_NODELAY:
      if(*(int*)optval) 
	  {
        tcp_nagle_disable(sock->conn->pcb.tcp);
      } 
	  else 
	  {
        tcp_nagle_enable(sock->conn->pcb.tcp);
      }
      break;
    case TCP_KEEPALIVE:
      sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
      break;

    default:
      break;
    }
    break;

  case IPPROTO_UDPLITE:
    switch (optname) 
	{
    case UDPLITE_SEND_CSCOV:
      if((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) 
	  {
        sock->conn->pcb.udp->chksum_len_tx = 8;
      } 
	  else 
	  {
        sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
      }
      break;
    case UDPLITE_RECV_CSCOV:
      if((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) 
	  {
        sock->conn->pcb.udp->chksum_len_rx = 8;
      } 
	  else 
	  {
        sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
      }
      break;
    default:
      break;
    }
    break;

  default:
    break;
  }
	
  /* 通知完成 */
  sys_sem_signal(&sock->conn->op_completed);
}

/* 设置IO属性 */
int lwip_ioctl(int s, long cmd, void *argp)
{
  /* 根据套接字描述符获取套接字结构体指针 */
  struct lwip_sock *sock = get_socket(s);
  u8_t val;

  if(!sock) 
  {
    return -1;
  }

  switch(cmd) 
  {
	/* 设置非阻塞 */
    case FIONBIO:
      val = 0;
      if(argp && *(u32_t*)argp) 
	  {
        val = 1;
      }
      netconn_set_nonblocking(sock->conn, val);
      sock_set_errno(sock, 0);
      return 0;

    default:
      sock_set_errno(sock, ENOSYS); /* not yet implemented */
      return -1;
  }
}

/* 文件属性操作 */
int lwip_fcntl(int s, int cmd, int val)
{
  struct lwip_sock *sock = get_socket(s);
  int ret = -1;

  if(!sock || !sock->conn) 
	{
    return -1;
  }

  switch(cmd) 
  {
	case F_GETFL:
	  ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
	  break;
	case F_SETFL:
	  if((val & ~O_NONBLOCK) == 0) 
	  {
		netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
		ret = 0;
	  }
	  break;

	default:
	  break;
  }

  return ret;
}
           

继续阅读