Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

sockets.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
00003  * All rights reserved. 
00004  * 
00005  * Redistribution and use in source and binary forms, with or without modification, 
00006  * are permitted provided that the following conditions are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright notice,
00009  *    this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright notice,
00011  *    this list of conditions and the following disclaimer in the documentation
00012  *    and/or other materials provided with the distribution.
00013  * 3. The name of the author may not be used to endorse or promote products
00014  *    derived from this software without specific prior written permission. 
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00017  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00018  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00019  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00020  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00021  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00024  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00025  * OF SUCH DAMAGE.
00026  *
00027  * This file is part of the lwIP TCP/IP stack.
00028  * 
00029  * Author: Adam Dunkels <adam@sics.se>
00030  *
00031  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
00032  *
00033  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00034  *            Departamento de Informática de Sistemas y Computadores          
00035  *            Universidad Politécnica de Valencia                             
00036  *            Valencia (Spain)    
00037  *            Date: April 2003                                          
00038  *
00039  */
00040 
00041 #include "lwip/opt.h"
00042 #include "lwip/api.h"
00043 #include "lwip/arch.h"
00044 #include "lwip/sys.h"
00045 
00046 #include "lwip/sockets.h"
00047 
00048 #define htons HTONS
00049 #define htonl HTONL
00050 
00051 #define NUM_SOCKETS MEMP_NUM_NETCONN
00052 
00053 struct lwip_socket {
00054   struct netconn *conn;
00055   struct netbuf *lastdata;
00056   u16_t lastoffset;
00057   u16_t rcvevent;
00058   u16_t sendevent;
00059   u16_t flags;
00060   int err;
00061 };
00062 
00063 struct lwip_select_cb 
00064 {
00065     struct lwip_select_cb *next;
00066     fd_set *readset;
00067     fd_set *writeset;
00068     fd_set *exceptset;
00069     int sem_signalled;
00070     sys_sem_t sem;
00071 };
00072 
00073 static struct lwip_socket sockets[NUM_SOCKETS];
00074 static struct lwip_select_cb *select_cb_list = 0;
00075 
00076 static sys_sem_t socksem = 0;
00077 static sys_sem_t selectsem = 0;
00078 
00079 static void
00080 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
00081 
00082 static int err_to_errno_table[11] = {
00083     0,                  /* ERR_OK    0      No error, everything OK. */
00084     ENOMEM,             /* ERR_MEM  -1      Out of memory error.     */
00085     ENOBUFS,            /* ERR_BUF  -2      Buffer error.            */
00086     ECONNABORTED,       /* ERR_ABRT -3      Connection aborted.      */
00087     ECONNRESET,         /* ERR_RST  -4      Connection reset.        */
00088     ESHUTDOWN,          /* ERR_CLSD -5      Connection closed.       */
00089     ENOTCONN,           /* ERR_CONN -6      Not connected.           */
00090     EINVAL,             /* ERR_VAL  -7      Illegal value.           */
00091     EIO,                /* ERR_ARG  -8      Illegal argument.        */
00092     EHOSTUNREACH,       /* ERR_RTE  -9      Routing problem.         */
00093     EADDRINUSE          /* ERR_USE  -10     Address in use.          */
00094 };
00095 
00096 #define err_to_errno(err) \
00097         ((err) < (sizeof(err_to_errno_table)/sizeof(int))) ? \
00098                 err_to_errno_table[-(err)] : EIO
00099 
00100 #ifdef ERRNO
00101 #define set_errno(err) errno = (err)
00102 #else
00103 #define set_errno(err)
00104 #endif
00105 
00106 #define sock_set_errno(sk, e) do { \
00107                         sk->err = (e); \
00108                         set_errno(sk->err); \
00109 } while(0)
00110 
00111 /*-----------------------------------------------------------------------------------*/
00112 static struct lwip_socket *
00113 get_socket(int s)
00114 {
00115   struct lwip_socket *sock;
00116   
00117   if((s < 0) || (s > NUM_SOCKETS)) {
00118         DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
00119         set_errno(EBADF);
00120     return NULL;
00121   }
00122   
00123   sock = &sockets[s];
00124 
00125   if(!sock->conn) {
00126         DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
00127         set_errno(EBADF);
00128     return NULL;
00129   }
00130 
00131   return sock;
00132 }
00133 /*-----------------------------------------------------------------------------------*/
00134 static int
00135 alloc_socket(struct netconn *newconn)
00136 {
00137   int i;
00138 
00139   if (!socksem)
00140       socksem = sys_sem_new(1);
00141 
00142   /* Protect socket array */
00143   sys_sem_wait(socksem);
00144   
00145   /* allocate a new socket identifier */
00146   for(i = 0; i < NUM_SOCKETS; ++i) {
00147     if(!sockets[i].conn) {
00148       sockets[i].conn = newconn;
00149       sockets[i].lastdata = NULL;
00150       sockets[i].lastoffset = 0;
00151       sockets[i].rcvevent = 0;
00152       sockets[i].sendevent = 1; /* TCP send buf is empty */
00153       sockets[i].flags = 0;
00154       sockets[i].err = 0;
00155       sys_sem_signal(socksem);
00156       return i;
00157     }
00158   }
00159   sys_sem_signal(socksem);
00160   return -1;
00161 }
00162 /*-----------------------------------------------------------------------------------*/
00163 int
00164 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
00165 {
00166   struct lwip_socket *sock;
00167   struct netconn *newconn;
00168   struct ip_addr naddr;
00169   u16_t port;
00170   int newsock;
00171   struct sockaddr_in sin;
00172 
00173   DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
00174   sock = get_socket(s);
00175   if(!sock) {
00176     return -1;
00177   }
00178   
00179   newconn = netconn_accept(sock->conn);
00180     
00181   /* get the IP address and port of the remote host */
00182   netconn_peer(newconn, &naddr, &port);
00183   
00184   memset(&sin, 0, sizeof(sin));
00185   sin.sin_len = sizeof(sin);
00186   sin.sin_family = AF_INET;
00187   sin.sin_port = htons(port);
00188   sin.sin_addr.s_addr = naddr.addr;
00189 
00190   if(*addrlen > sizeof(sin))
00191       *addrlen = sizeof(sin);
00192 
00193   memcpy(addr, &sin, *addrlen);
00194 
00195   newsock = alloc_socket(newconn);
00196   if(newsock == -1) {  
00197     netconn_delete(newconn);
00198         sock_set_errno(sock, ENOBUFS);
00199         return -1;
00200   }
00201   newconn->callback = event_callback;
00202   sock = get_socket(newsock);
00203   
00204   sys_sem_wait(socksem);
00205   sock->rcvevent += -1 - newconn->socket;
00206   newconn->socket = newsock;
00207   sys_sem_signal(socksem);
00208 
00209 #if SOCKETS_DEBUG
00210   DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
00211   ip_addr_debug_print(&naddr);
00212   DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));
00213 #endif
00214   
00215   sock_set_errno(sock, 0);
00216   return newsock;
00217 }
00218 /*-----------------------------------------------------------------------------------*/
00219 int
00220 lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
00221 {
00222   struct lwip_socket *sock;
00223   struct ip_addr local_addr;
00224   u16_t local_port;
00225   err_t err;
00226   
00227   sock = get_socket(s);
00228   if(!sock) {
00229     return -1;
00230   }
00231   
00232   local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
00233   local_port = ((struct sockaddr_in *)name)->sin_port;
00234 
00235 #if SOCKETS_DEBUG
00236   DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
00237   ip_addr_debug_print(&local_addr);
00238   DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));
00239 #endif
00240   
00241   err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
00242 
00243   if(err != ERR_OK) {
00244         DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
00245         sock_set_errno(sock, err_to_errno(err));
00246     return -1;
00247   }
00248 
00249   DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
00250   sock_set_errno(sock, 0);
00251   return 0;
00252 }
00253 /*-----------------------------------------------------------------------------------*/
00254 int
00255 lwip_close(int s)
00256 {
00257   struct lwip_socket *sock;
00258   
00259   DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
00260   if (!socksem)
00261       socksem = sys_sem_new(1);
00262 
00263   /* We cannot allow multiple closes of the same socket. */
00264   sys_sem_wait(socksem);
00265   
00266   sock = get_socket(s);
00267   if(!sock) {
00268       sys_sem_signal(socksem);
00269       return -1;
00270   }
00271   
00272   netconn_delete(sock->conn);
00273   if(sock->lastdata) {
00274     netbuf_delete(sock->lastdata);
00275   }
00276   sock->lastdata = NULL;
00277   sock->lastoffset = 0;
00278   sock->conn = NULL;
00279   sys_sem_signal(socksem);
00280   sock_set_errno(sock, 0);
00281   return 0;
00282 }
00283 /*-----------------------------------------------------------------------------------*/
00284 int
00285 lwip_connect(int s, struct sockaddr *name, socklen_t namelen)
00286 {
00287   struct lwip_socket *sock;
00288   err_t err;
00289 
00290   sock = get_socket(s);
00291   if(!sock) {
00292     return -1;
00293   }
00294   
00295   if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
00296         DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
00297         err = netconn_disconnect(sock->conn);
00298   } else {
00299         struct ip_addr remote_addr;
00300         u16_t remote_port;
00301 
00302         remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
00303         remote_port = ((struct sockaddr_in *)name)->sin_port;
00304 
00305 #if SOCKETS_DEBUG
00306         DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
00307         ip_addr_debug_print(&remote_addr);
00308         DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));
00309 #endif
00310         
00311         err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
00312    }
00313 
00314   if(err != ERR_OK) {
00315         DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
00316         sock_set_errno(sock, err_to_errno(err));
00317     return -1;
00318   }
00319 
00320   DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
00321   sock_set_errno(sock, 0);
00322   return 0;
00323 }
00324 /*-----------------------------------------------------------------------------------*/
00325 int
00326 lwip_listen(int s, int backlog)
00327 {
00328   struct lwip_socket *sock;    
00329   err_t err;
00330   
00331   DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
00332   sock = get_socket(s);
00333   if(!sock) {
00334     return -1;
00335   }
00336  
00337   err = netconn_listen(sock->conn);
00338 
00339   if(err != ERR_OK) {
00340         DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
00341         sock_set_errno(sock, err_to_errno(err));
00342     return -1;
00343   }
00344 
00345   sock_set_errno(sock, 0);
00346   return 0;
00347 }
00348 /*-----------------------------------------------------------------------------------*/
00349 int
00350 lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
00351               struct sockaddr *from, socklen_t *fromlen)
00352 {
00353   struct lwip_socket *sock;
00354   struct netbuf *buf;
00355   u16_t buflen, copylen;
00356   struct ip_addr *addr;
00357   u16_t port;
00358 
00359   
00360   DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));
00361   sock = get_socket(s);
00362   if(!sock) {
00363     return -1;
00364   }
00365 
00366   /* Check if there is data left from the last recv operation. */
00367   if(sock->lastdata) {    
00368     buf = sock->lastdata;
00369   } else {
00370     /* If this is non-blocking call, then check first */
00371     if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK))
00372         && !sock->rcvevent)
00373     {
00374       DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
00375       sock_set_errno(sock, EWOULDBLOCK);
00376       return -1;
00377     }
00378       
00379     /* No data was left from the previous operation, so we try to get
00380        some from the network. */
00381     buf = netconn_recv(sock->conn);
00382     
00383     if(!buf) {
00384       /* We should really do some error checking here. */
00385       DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
00386       sock_set_errno(sock, 0);
00387       return 0;
00388     }
00389   }
00390   
00391   buflen = netbuf_len(buf);
00392 
00393   buflen -= sock->lastoffset;
00394   
00395   if(len > buflen) {
00396     copylen = buflen;
00397   } else {
00398     copylen = len;
00399   }
00400   
00401   /* copy the contents of the received buffer into
00402      the supplied memory pointer mem */
00403   netbuf_copy_partial(buf, mem, copylen, sock->lastoffset);
00404 
00405   /* Check to see from where the data was. */
00406   if(from && fromlen) {
00407     struct sockaddr_in sin;
00408 
00409     addr = netbuf_fromaddr(buf);
00410     port = netbuf_fromport(buf);
00411 
00412     memset(&sin, 0, sizeof(sin));
00413     sin.sin_len = sizeof(sin);
00414     sin.sin_family = AF_INET;
00415     sin.sin_port = htons(port);
00416     sin.sin_addr.s_addr = addr->addr;
00417 
00418     if(*fromlen > sizeof(sin))
00419       *fromlen = sizeof(sin);
00420 
00421     memcpy(from, &sin, *fromlen);
00422 
00423 #if SOCKETS_DEBUG
00424     DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
00425     ip_addr_debug_print(addr);
00426     DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
00427 #endif
00428   } else {
00429 #if SOCKETS_DEBUG > 0
00430     addr = netbuf_fromaddr(buf);
00431     port = netbuf_fromport(buf);  
00432 
00433     DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
00434     ip_addr_debug_print(addr);
00435     DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
00436 #endif
00437 
00438   }
00439  
00440   /* If this is a TCP socket, check if there is data left in the
00441      buffer. If so, it should be saved in the sock structure for next
00442      time around. */
00443   if(netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) {
00444     sock->lastdata = buf;
00445     sock->lastoffset += copylen;
00446   } else {
00447     sock->lastdata = NULL;
00448     sock->lastoffset = 0;
00449     netbuf_delete(buf);
00450   }
00451 
00452  
00453   sock_set_errno(sock, 0);
00454   return copylen;
00455 }
00456 /*-----------------------------------------------------------------------------------*/
00457 int
00458 lwip_read(int s, void *mem, int len)
00459 {
00460   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
00461 }
00462 /*-----------------------------------------------------------------------------------*/
00463 int
00464 lwip_recv(int s, void *mem, int len, unsigned int flags)
00465 {
00466   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
00467 }
00468 /*-----------------------------------------------------------------------------------*/
00469 int
00470 lwip_send(int s, void *data, int size, unsigned int flags)
00471 {
00472   struct lwip_socket *sock;
00473   struct netbuf *buf;
00474   err_t err;
00475 
00476   DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", s, data, size, flags));
00477 
00478   sock = get_socket(s);
00479   if(!sock) {
00480     return -1;
00481   }  
00482   
00483   switch(netconn_type(sock->conn)) {
00484   case NETCONN_UDP:
00485     /* create a buffer */
00486     buf = netbuf_new();
00487 
00488     if(!buf) {
00489           DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ENOBUFS\n", s));
00490           sock_set_errno(sock, ENOBUFS);
00491       return -1;
00492     }
00493     
00494     /* make the buffer point to the data that should
00495        be sent */
00496     netbuf_ref(buf, data, size);
00497 
00498     /* send the data */
00499     err = netconn_send(sock->conn, buf);
00500 
00501     /* deallocated the buffer */
00502     netbuf_delete(buf);
00503     break;
00504   case NETCONN_TCP:
00505     err = netconn_write(sock->conn, data, size, NETCONN_COPY);
00506     break;
00507   default:
00508     err = ERR_ARG;
00509     break;
00510   }
00511   if(err != ERR_OK) {
00512         DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d\n", s, err));
00513         sock_set_errno(sock, err_to_errno(err));
00514     return -1;    
00515   }
00516 
00517   DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ok size=%d\n", s, size));
00518   sock_set_errno(sock, 0);
00519   return size;
00520 }
00521 /*-----------------------------------------------------------------------------------*/
00522 int
00523 lwip_sendto(int s, void *data, int size, unsigned int flags,
00524        struct sockaddr *to, socklen_t tolen)
00525 {
00526   struct lwip_socket *sock;
00527   struct ip_addr remote_addr, addr;
00528   u16_t remote_port, port;
00529   int ret,connected;
00530 
00531   sock = get_socket(s);
00532   if(!sock) {
00533     return -1;
00534   }
00535   
00536   /* get the peer if currently connected */
00537   connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK);
00538   
00539   remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
00540   remote_port = ((struct sockaddr_in *)to)->sin_port;
00541 
00542 #if SOCKETS_DEBUG
00543   DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, size, flags));
00544   ip_addr_debug_print(&remote_addr);
00545   DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port)));
00546 #endif
00547   
00548   netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
00549   
00550   ret = lwip_send(s, data, size, flags);
00551 
00552   /* reset the remote address and port number
00553      of the connection */
00554   if(connected)
00555         netconn_connect(sock->conn, &addr, port);
00556   else
00557         netconn_disconnect(sock->conn);
00558   return ret;
00559 }
00560 /*-----------------------------------------------------------------------------------*/
00561 int
00562 lwip_socket(int domain, int type, int protocol)
00563 {
00564   struct netconn *conn;
00565   int i;
00566 
00567   /* create a netconn */
00568   switch(type) {
00569   case SOCK_DGRAM:
00570     conn = netconn_new_with_callback(NETCONN_UDP, event_callback);
00571         DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
00572     break;
00573   case SOCK_STREAM:
00574     conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
00575         DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
00576     break;
00577   default:
00578         DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", domain, type, protocol));
00579         set_errno(EINVAL);
00580     return -1;
00581   }
00582 
00583   if(!conn) {
00584     DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
00585         set_errno(ENOBUFS);
00586     return -1;
00587   }
00588 
00589   i = alloc_socket(conn);
00590 
00591   if(i == -1) {
00592     netconn_delete(conn);
00593         set_errno(ENOBUFS);
00594         return -1;
00595   }
00596   conn->socket = i;
00597   DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
00598   set_errno(0);
00599   return i;
00600 }
00601 /*-----------------------------------------------------------------------------------*/
00602 int
00603 lwip_write(int s, void *data, int size)
00604 {
00605    return lwip_send(s, data, size, 0);
00606 }
00607 
00608 /*-----------------------------------------------------------------------------------*/
00609 static int
00610 lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
00611 {
00612     int i, nready = 0;
00613     fd_set lreadset, lwriteset, lexceptset;
00614     struct lwip_socket *p_sock;
00615 
00616     FD_ZERO(&lreadset);
00617     FD_ZERO(&lwriteset);
00618     FD_ZERO(&lexceptset);
00619     
00620     /* Go through each socket in each list to count number of sockets which
00621        currently match */
00622     for(i = 0; i < maxfdp1; i++)
00623     {
00624         if(FD_ISSET(i, readset))
00625         {
00626             /* See if netconn of this socket is ready for read */
00627             p_sock = get_socket(i);
00628             if (p_sock && (p_sock->lastdata || p_sock->rcvevent))
00629             {
00630                 FD_SET(i, &lreadset);
00631                         DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
00632                 nready++;
00633             }
00634         }
00635         if(FD_ISSET(i, writeset))
00636         {
00637             /* See if netconn of this socket is ready for write */
00638             p_sock = get_socket(i);
00639             if (p_sock && p_sock->sendevent)
00640             {
00641                 FD_SET(i, &lwriteset);
00642                         DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
00643                 nready++;
00644             }
00645         }
00646     }
00647     *readset = lreadset;
00648     *writeset = lwriteset;
00649     FD_ZERO(exceptset);
00650 
00651     return nready;
00652 }
00653 
00654 
00655 /*-----------------------------------------------------------------------------------*/
00656 int
00657 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
00658                struct timeval *timeout)
00659 {
00660     int i;
00661     int nready;
00662     fd_set lreadset, lwriteset, lexceptset;
00663     u32_t msectimeout;
00664     struct lwip_select_cb select_cb;
00665     struct lwip_select_cb *p_selcb;
00666 
00667         DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));
00668     select_cb.next = 0;
00669     select_cb.readset = readset;
00670     select_cb.writeset = writeset;
00671     select_cb.exceptset = exceptset;
00672     select_cb.sem_signalled = 0;
00673     
00674     /* Protect ourselves searching through the list */
00675     if (!selectsem)
00676         selectsem = sys_sem_new(1);
00677     sys_sem_wait(selectsem);
00678     
00679     if (readset)
00680         lreadset = *readset;
00681     else
00682         FD_ZERO(&lreadset);
00683     if (writeset)
00684         lwriteset = *writeset;
00685     else
00686         FD_ZERO(&lwriteset);
00687     if (exceptset)
00688         lexceptset = *exceptset;
00689     else
00690         FD_ZERO(&lexceptset);
00691     
00692     /* Go through each socket in each list to count number of sockets which
00693        currently match */
00694     nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
00695     
00696     /* If we don't have any current events, then suspend if we are supposed to */
00697     if (!nready)
00698     {
00699         if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
00700         {
00701             sys_sem_signal(selectsem);
00702             if (readset)
00703                 FD_ZERO(readset);
00704             if (writeset)
00705                 FD_ZERO(writeset);
00706             if (exceptset)
00707                 FD_ZERO(exceptset);
00708 
00709                         DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
00710                         set_errno(0);
00711             return 0;
00712         }
00713         
00714         /* add our semaphore to list */
00715         /* We don't actually need any dynamic memory. Our entry on the
00716          * list is only valid while we are in this function, so it's ok
00717          * to use local variables */
00718 
00719         select_cb.sem = sys_sem_new(0);
00720         /* Note that we are still protected */
00721         /* Put this select_cb on top of list */
00722         select_cb.next = select_cb_list;
00723         select_cb_list = &select_cb;
00724 
00725         /* Now we can safely unprotect */
00726         sys_sem_signal(selectsem);
00727 
00728         /* Now just wait to be woken */
00729         if (timeout == 0)
00730             /* Wait forever */
00731             msectimeout = 0;
00732         else
00733             msectimeout =  ((timeout->tv_sec * 1000) + (timeout->tv_usec /1000));
00734 
00735         i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
00736 
00737         /* Take us off the list */
00738         sys_sem_wait(selectsem);
00739         if (select_cb_list == &select_cb)
00740             select_cb_list = select_cb.next;
00741         else
00742             for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next)
00743                 if (p_selcb->next == &select_cb)
00744                 {
00745                     p_selcb->next = select_cb.next;
00746                     break;
00747                 }
00748         
00749         sys_sem_signal(selectsem);
00750         
00751         sys_sem_free(select_cb.sem);
00752         if (i == 0)             /* Timeout */
00753         {
00754             if (readset)
00755                 FD_ZERO(readset);
00756             if (writeset)
00757                 FD_ZERO(writeset);
00758             if (exceptset)
00759                 FD_ZERO(exceptset);
00760                         DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
00761                         set_errno(0);
00762             return 0;
00763         }
00764 
00765         if (readset)
00766             lreadset = *readset;
00767         else
00768             FD_ZERO(&lreadset);
00769         if (writeset)
00770             lwriteset = *writeset;
00771         else
00772             FD_ZERO(&lwriteset);
00773         if (exceptset)
00774             lexceptset = *exceptset;
00775         else
00776             FD_ZERO(&lexceptset);
00777 
00778         /* See what's set */
00779         nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
00780     }
00781     else
00782         sys_sem_signal(selectsem);
00783     
00784     if (readset)
00785         *readset = lreadset;
00786     if (writeset)
00787         *writeset = lwriteset;
00788     if (exceptset)
00789         *exceptset = lexceptset;
00790         DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
00791         set_errno(0);
00792     return nready;
00793 }
00794 
00795 /*-----------------------------------------------------------------------------------*/
00796 static void
00797 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
00798 {
00799     int s;
00800     struct lwip_socket *sock;
00801     struct lwip_select_cb *scb;
00802     
00803     /* Get socket */
00804     if (conn)
00805     {
00806         s = conn->socket;
00807         if (s < 0)
00808         {
00809             /* Data comes in right away after an accept, even though
00810              * the server task might not have created a new socket yet.
00811              * Just count down (or up) if that's the case and we
00812              * will use the data later. Note that only receive events
00813              * can happen before the new socket is set up. */
00814             if (evt == NETCONN_EVT_RCVPLUS)
00815                 conn->socket--;
00816             return;
00817         }
00818         
00819         sock = get_socket(s);
00820         if (!sock)
00821             return;
00822     }
00823     else
00824         return;
00825 
00826     if (!selectsem)
00827         selectsem = sys_sem_new(1);
00828     
00829     sys_sem_wait(selectsem);
00830     /* Set event as required */
00831     switch (evt)
00832     {
00833       case NETCONN_EVT_RCVPLUS:
00834         sock->rcvevent++;
00835         break;
00836       case NETCONN_EVT_RCVMINUS:
00837         sock->rcvevent--;
00838         break;
00839       case NETCONN_EVT_SENDPLUS:
00840         sock->sendevent = 1;
00841         break;
00842       case NETCONN_EVT_SENDMINUS:
00843         sock->sendevent = 0;
00844         break;
00845     }
00846     sys_sem_signal(selectsem);
00847     
00848     /* Now decide if anyone is waiting for this socket */
00849     /* NOTE: This code is written this way to protect the select link list
00850        but to avoid a deadlock situation by releasing socksem before
00851        signalling for the select. This means we need to go through the list
00852        multiple times ONLY IF a select was actually waiting. We go through
00853        the list the number of waiting select calls + 1. This list is
00854        expected to be small. */
00855     while (1)
00856     {
00857         sys_sem_wait(selectsem);
00858         for (scb = select_cb_list; scb; scb = scb->next)
00859         {
00860             if (scb->sem_signalled == 0)
00861             {
00862                 /* Test this select call for our socket */
00863                 if (scb->readset && FD_ISSET(s, scb->readset))
00864                     if (sock->rcvevent)
00865                         break;
00866                 if (scb->writeset && FD_ISSET(s, scb->writeset))
00867                     if (sock->sendevent)
00868                         break;
00869             }
00870         }
00871         if (scb)
00872         {
00873             scb->sem_signalled = 1;
00874             sys_sem_signal(selectsem);
00875             sys_sem_signal(scb->sem);
00876         } else {
00877             sys_sem_signal(selectsem);
00878             break;
00879         }
00880     }
00881     
00882 }
00883 
00884 /*-----------------------------------------------------------------------------------*/
00885 
00886 
00887 int lwip_shutdown(int s, int how)
00888 {
00889         DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
00890     return lwip_close(s); /* XXX temporary hack until proper implementation */
00891 }
00892 
00893 int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen)
00894 {
00895   struct lwip_socket *sock;
00896   struct sockaddr_in sin;
00897   struct ip_addr naddr;
00898 
00899   sock = get_socket(s);
00900   if(!sock) {
00901     return -1;
00902   }
00903   
00904   memset(&sin, 0, sizeof(sin));
00905   sin.sin_len = sizeof(sin);
00906   sin.sin_family = AF_INET;
00907 
00908   /* get the IP address and port of the remote host */
00909   netconn_peer(sock->conn, &naddr, &sin.sin_port);
00910   
00911 #if SOCKETS_DEBUG
00912   DEBUGF(SOCKETS_DEBUG, ("lwip_getpeername(%d, addr=", s));
00913   ip_addr_debug_print(&naddr);
00914   DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
00915 #endif
00916   
00917   sin.sin_port = htons(sin.sin_port);
00918   sin.sin_addr.s_addr = naddr.addr;
00919 
00920   if(*namelen > sizeof(sin))
00921       *namelen = sizeof(sin);
00922 
00923   memcpy(name, &sin, *namelen);
00924   sock_set_errno(sock, 0);
00925   return 0;
00926 }
00927 
00928 int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen)
00929 {
00930   struct lwip_socket *sock;
00931   struct sockaddr_in sin;
00932   struct ip_addr *naddr;
00933 
00934   sock = get_socket(s);
00935   if(!sock) {
00936     return -1;
00937   }
00938   
00939   memset(&sin, 0, sizeof(sin));
00940   sin.sin_len = sizeof(sin);
00941   sin.sin_family = AF_INET;
00942 
00943   /* get the IP address and port of the remote host */
00944   netconn_addr(sock->conn, &naddr, &sin.sin_port);
00945 
00946 #if SOCKETS_DEBUG
00947   DEBUGF(SOCKETS_DEBUG, ("lwip_getsockname(%d, addr=", s));
00948   ip_addr_debug_print(naddr);
00949   DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
00950 #endif
00951   
00952   sin.sin_port = htons(sin.sin_port);
00953   sin.sin_addr.s_addr = naddr->addr;
00954 
00955   if(*namelen > sizeof(sin))
00956       *namelen = sizeof(sin);
00957 
00958   memcpy(name, &sin, *namelen);
00959   sock_set_errno(sock, 0);
00960   return 0;
00961 }
00962 
00963 int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
00964 {
00965         int err = ENOSYS;
00966         struct lwip_socket *sock = get_socket(s);
00967 
00968         if(!sock) {
00969                 return -1;
00970         }
00971 
00972         if(level == SOL_SOCKET) {
00973                 switch(optname) {
00974                         case SO_ERROR:
00975                                 if(!optval || !optlen || (*optlen != sizeof(int))) {
00976                                         err = EINVAL;
00977                                         break;
00978                                 }
00979                                 *(int *)optval = sock->err;
00980                                 sock->err = 0;
00981                                 DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval));
00982                                 err = 0;
00983                                 break;
00984                         default:
00985                                 DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
00986                                 break;
00987                 }
00988         } else {
00989                 DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
00990         }
00991         sock_set_errno(sock, err);
00992         return err ? -1 : 0;
00993 }
00994 
00995 int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
00996 {
00997         struct lwip_socket *sock = get_socket(s);
00998         int err = ENOSYS;
00999 
01000         if(!sock) {
01001                 return -1;
01002         }
01003 
01004         if(level == SOL_SOCKET) {
01005                 switch(optname) {
01006                         case SO_REUSEADDR:
01007                                 DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, SO_REUSEADDR, ..)\n", s));
01008                                 /* XXX just pretend we support this for now */
01009                                 err = 0;
01010                                 break;
01011                         default:
01012                                 DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
01013                                 break;
01014                 }
01015         } else {
01016                 DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
01017         }
01018 
01019         sock_set_errno(sock, err);
01020         return err ? -1 : 0;
01021 }
01022 
01023 int lwip_ioctl(int s, long cmd, void *argp)
01024 {
01025         struct lwip_socket *sock = get_socket(s);
01026 
01027         if(!sock) {
01028                 return -1;
01029         }
01030 
01031         switch(cmd) {
01032         case FIONREAD:
01033                 if(!argp) {
01034                         sock_set_errno(sock, EINVAL);
01035                         return -1;
01036                 }
01037 
01038                 *((u16_t*)argp) = sock->conn->recv_avail;
01039 
01040                 DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));
01041                 sock_set_errno(sock, 0);
01042                 return 0;
01043 
01044         case FIONBIO:
01045                 if(argp && *(u32_t*)argp)
01046                         sock->flags |= O_NONBLOCK;
01047                 else
01048                         sock->flags &= ~O_NONBLOCK;
01049                 DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));
01050                 sock_set_errno(sock, 0);
01051                 return 0;
01052 
01053         default:
01054                 DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
01055                 sock_set_errno(sock, ENOSYS); /* not yet implemented */
01056                 return -1;
01057         }
01058 }
01059 

Generated on Wed Jan 14 12:58:57 2004 for RTL-lwIP-0.4 by doxygen 1.3.4