www.pudn.com > ucosii4skyeye184.rar > sockets.c, change:2003-05-17,size:11508b


/* 
 * Copyright (c) 2001, Swedish Institute of Computer Science. 
 * All rights reserved.  
 * 
 * Redistribution and use in source and binary forms, with or without  
 * modification, are permitted provided that the following conditions  
 * are met:  
 * 1. Redistributions of source code must retain the above copyright  
 *    notice, this list of conditions and the following disclaimer.  
 * 2. Redistributions in binary form must reproduce the above copyright  
 *    notice, this list of conditions and the following disclaimer in the  
 *    documentation and/or other materials provided with the distribution.  
 * 3. Neither the name of the Institute nor the names of its contributors  
 *    may be used to endorse or promote products derived from this software  
 *    without specific prior written permission.  
 * 
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND  
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE  
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  
 * SUCH DAMAGE.  
 * 
 * This file is part of the lwIP TCP/IP stack. 
 *  
 * Author: Adam Dunkels <adam@sics.se> 
 * 
 * $Id: sockets.c,v 1.1.1.1 2003/05/17 05:06:56 chenyu Exp $ 
 */ 
 
#include "lwip/debug.h" 
#include "lwip/api.h" 
 
#include "lwip/sockets.h" 
 
#define NUM_SOCKETS 10 
 
struct lwip_socket { 
  struct netconn *conn; 
  struct netbuf *lastdata; 
  u16_t lastoffset; 
}; 
 
static struct lwip_socket sockets[NUM_SOCKETS]; 
 
/*-----------------------------------------------------------------------------------*/ 
static struct lwip_socket * 
get_socket(int s) 
{ 
  struct lwip_socket *sock; 
   
  if(s > NUM_SOCKETS) { 
    /* errno = EBADF; */ 
    return NULL; 
  } 
   
  sock = &sockets[s]; 
 
  if(sock->conn == NULL) { 
    /* errno = EBADF; */ 
    return NULL; 
  } 
  return sock; 
} 
/*-----------------------------------------------------------------------------------*/ 
static int 
alloc_socket(struct netconn *newconn) 
{ 
  int i; 
   
  /* allocate a new socket identifier */ 
  for(i = 0; i < NUM_SOCKETS; ++i) { 
    if(sockets[i].conn == NULL) { 
      sockets[i].conn = newconn; 
      sockets[i].lastdata = NULL; 
      sockets[i].lastoffset = 0; 
      return i; 
    } 
  } 
  return -1; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_accept(int s, struct sockaddr *addr, int *addrlen) 
{ 
  struct lwip_socket *sock; 
  struct netconn *newconn; 
  struct ip_addr *naddr; 
  u16_t port; 
  int newsock; 
 
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  } 
   
  newconn = netconn_accept(sock->conn); 
     
  /* get the IP address and port of the remote host */ 
  netconn_peer(newconn, &naddr, &port); 
   
  ((struct sockaddr_in *)addr)->sin_addr.s_addr = naddr->addr; 
  ((struct sockaddr_in *)addr)->sin_port = port; 
 
  newsock = alloc_socket(newconn); 
  if(newsock == -1) {   
    netconn_delete(newconn); 
    /* errno = ENOBUFS; */ 
  } 
  return newsock; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_bind(int s, struct sockaddr *name, int namelen) 
{ 
  struct lwip_socket *sock; 
  struct ip_addr remote_addr; 
  u16_t remote_port; 
  err_t err; 
   
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  } 
   
  remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; 
  remote_port = ((struct sockaddr_in *)name)->sin_port; 
   
  err = netconn_bind(sock->conn, &remote_addr, ntohs(remote_port)); 
 
  if(err != ERR_OK) { 
    /* errno = ... */ 
    return -1; 
  } 
 
  return 0; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_close(int s) 
{ 
  struct lwip_socket *sock; 
   
  DEBUGF(SOCKETS_DEBUG, ("close: socket %d\n", s)); 
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  } 
   
   
  netconn_delete(sock->conn); 
  if(sock->lastdata != NULL) { 
    netbuf_delete(sock->lastdata); 
  } 
  sock->lastdata = NULL; 
  sock->lastoffset = 0; 
  sock->conn = NULL; 
  return 0; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_connect(int s, struct sockaddr *name, int namelen) 
{ 
  struct lwip_socket *sock; 
  struct ip_addr remote_addr; 
  u16_t remote_port; 
  err_t err; 
 
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  } 
   
  remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; 
  remote_port = ((struct sockaddr_in *)name)->sin_port; 
   
  err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); 
 
  if(err != ERR_OK) { 
    /* errno = ... */ 
    return -1; 
  } 
 
  return 0; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_listen(int s, int backlog) 
{ 
  struct lwip_socket *sock;     
  err_t err; 
   
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  } 
  
  err = netconn_listen(sock->conn); 
 
  if(err != ERR_OK) { 
    /* errno = ... */ 
    return -1; 
  } 
 
  return 0; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_recvfrom(int s, void *mem, int len, unsigned int flags, 
	      struct sockaddr *from, int *fromlen) 
{ 
  struct lwip_socket *sock; 
  struct netbuf *buf; 
  u16_t buflen, copylen; 
  struct ip_addr *addr; 
  u16_t port; 
 
   
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  } 
 
  /* Check if there is data left from the last recv operation. */ 
  if(sock->lastdata != NULL) {     
    buf = sock->lastdata; 
  } else { 
    /* No data was left from the previous operation, so we try to get 
       some from the network. */ 
    buf = netconn_recv(sock->conn); 
     
    if(buf == NULL) { 
      /* We should really do some error checking here. */ 
      return 0; 
    } 
  } 
   
  buflen = netbuf_len(buf); 
 
  buflen -= sock->lastoffset; 
   
  if(len > buflen) { 
    copylen = buflen; 
  } else { 
    copylen = len; 
  } 
   
  /* copy the contents of the received buffer into 
     the supplied memory pointer mem */ 
  netbuf_copy_partial(buf, mem, copylen, sock->lastoffset); 
 
  /* If this is a TCP socket, check if there is data left in the 
     buffer. If so, it should be saved in the sock structure for next 
     time around. */ 
  if(netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) { 
    sock->lastdata = buf; 
    sock->lastoffset = buflen - copylen; 
  } else { 
    sock->lastdata = NULL; 
    sock->lastoffset = 0; 
    netbuf_delete(buf); 
  } 
 
  /* Check to see from where the data was. */ 
  if(from != NULL && fromlen != NULL) { 
    addr = netbuf_fromaddr(buf); 
    port = htons(netbuf_fromport(buf));   
    ((struct sockaddr_in *)from)->sin_addr.s_addr = addr->addr; 
    ((struct sockaddr_in *)from)->sin_port = port; 
    *fromlen = sizeof(struct sockaddr_in); 
  } 
 
   
  /* if the length of the received data is larger than 
     len, this data is discarded and we return len. 
     otherwise we return the actual length of the received 
     data */ 
  if(len > copylen) { 
    return copylen; 
  } else { 
    return len; 
  } 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_read(int s, void *mem, int len) 
{ 
  return lwip_recv(s, mem, len, 0); 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_recv(int s, void *mem, int len, unsigned int flags) 
{ 
  return lwip_recvfrom(s, mem, len, flags, NULL, NULL); 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_send(int s, void *data, int size, unsigned int flags) 
{ 
  struct lwip_socket *sock; 
  struct netbuf *buf; 
  err_t err; 
 
  DEBUGF(SOCKETS_DEBUG, ("send: socket %d, size %d\n", s, size)); 
 
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  }   
   
  switch(netconn_type(sock->conn)) { 
  case NETCONN_UDP: 
    /* create a buffer */ 
    buf = netbuf_new(); 
 
    if(buf == NULL) { 
      /* errno = ENOBUFS; */ 
      return -1; 
    } 
     
    /* make the buffer point to the data that should 
       be sent */ 
    netbuf_ref(buf, data, size); 
 
    /* send the data */ 
    err = netconn_send(sock->conn, buf); 
 
    /* deallocated the buffer */ 
    netbuf_delete(buf); 
    break; 
  case NETCONN_TCP: 
    err = netconn_write(sock->conn, data, size, NETCONN_COPY); 
    break; 
  default: 
    err = ERR_ARG; 
    break; 
  } 
  if(err != ERR_OK) { 
    /* errno = ... */ 
    return -1;     
  } 
     
  return size; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_sendto(int s, void *data, int size, unsigned int flags, 
       struct sockaddr *to, int tolen) 
{ 
  struct lwip_socket *sock; 
  struct ip_addr remote_addr, *addr; 
  u16_t remote_port, port; 
  int ret; 
 
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  } 
   
  /* get the peer if currently connected */ 
  netconn_peer(sock->conn, &addr, &port); 
   
  remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; 
  remote_port = ((struct sockaddr_in *)to)->sin_port; 
  netconn_connect(sock->conn, &remote_addr, remote_port); 
   
  ret = lwip_send(s, data, size, flags); 
 
  /* reset the remote address and port number 
     of the connection */ 
  netconn_connect(sock->conn, addr, port); 
  return ret; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_socket(int domain, int type, int protocol) 
{ 
  struct netconn *conn; 
  int i; 
 
  /* create a netconn */ 
  switch(type) { 
  case SOCK_DGRAM: 
    conn = netconn_new(NETCONN_UDP); 
    break; 
  case SOCK_STREAM: 
    conn = netconn_new(NETCONN_TCP); 
    break; 
  default: 
    /* errno = ... */ 
    return -1; 
  } 
 
  if(conn == NULL) { 
    DEBUGF(SOCKETS_DEBUG, ("socket: could not create netconn.\n")); 
    /* errno = ENOBUFS; */ 
    return -1; 
  } 
 
  i = alloc_socket(conn); 
 
  if(i == -1) { 
    /* errno = ENOBUFS; */ 
    netconn_delete(conn); 
  } 
  return i; 
} 
/*-----------------------------------------------------------------------------------*/ 
int 
lwip_write(int s, void *data, int size) 
{ 
  struct lwip_socket *sock; 
  err_t err; 
 
  DEBUGF(SOCKETS_DEBUG, ("write: socket %d, size %d\n", s, size)); 
 
  sock = get_socket(s); 
  if(sock == NULL) { 
    return -1; 
  } 
     
  switch(netconn_type(sock->conn)) { 
  case NETCONN_UDP: 
    return lwip_send(s, data, size, 0); 
 
  case NETCONN_TCP: 
    err = netconn_write(sock->conn, data, size, NETCONN_COPY); 
    break; 
  default: 
    err = ERR_ARG; 
    break; 
  } 
  if(err != ERR_OK) { 
    /* errno = ... */ 
    return -1; 
  } 
  return size; 
} 
/*-----------------------------------------------------------------------------------*/