- Main Page
- Data Structures
- Files
- Directories

- Search for |

- File List
- Globals

# api_lib.c

Go to the documentation of this file.

    00001 /*
    00002  * Copyright (c) 2001, Swedish Institute of Computer Science.
    00003  * All rights reserved.
    00004  *
    00005  * Redistribution and use in source and binary forms, with or without
    00006  * modification, are permitted provided that the following conditions
    00007  * are met:
    00008  * 1. Redistributions of source code must retain the above copyright
    00009  *    notice, this list of conditions and the following disclaimer.
    00010  * 2. Redistributions in binary form must reproduce the above copyright
    00011  *    notice, this list of conditions and the following disclaimer in the
    00012  *    documentation and/or other materials provided with the distribution.
    00013  * 3. Neither the name of the Institute nor the names of its contributors
    00014  *    may be used to endorse or promote products derived from this software
    00015  *    without specific prior written permission.
    00016  *
    00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
    00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
    00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    00027  * SUCH DAMAGE.
    00028  *
    00029  * This file is part of the lwIP TCP/IP stack.
    00030  *
    00031  * Author: Adam Dunkels <adam@sics.se>
    00032  *
    00033  * $Id: api__lib_8c-source.html 88 2016-01-12 00:11:29Z reddawg $
    00034  */
    00035
    00036 /* This is the part of the API that is linked with
    00037    the application */
    00038
    00039 #include <ubixos/types.h>
    00040
    00041 #include "net/debug.h"
    00042 #include "net/api.h"
    00043 #include "net/api_msg.h"
    00044 #include "net/memp.h"
    00045
    00046 #include "net/debug.h"
    00047
    00048 #include "lib/kprintf.h"
    00049 /*-----------------------------------------------------------------------------------*/
    00050 struct
    00051 netbuf *netbuf_new(void)
    00052 {
    00053   struct netbuf *buf;
    00054
    00055   buf = memp_mallocp(MEMP_NETBUF);
    00056   if(buf != NULL) {
    00057     buf->p = NULL;
    00058     buf->ptr = NULL;
    00059     return buf;
    00060   } else {
    00061     return NULL;
    00062   }
    00063 }
    00064 /*-----------------------------------------------------------------------------------*/
    00065 void
    00066 netbuf_delete(struct netbuf *buf)
    00067 {
    00068   if(buf != NULL) {
    00069     if(buf->p != NULL) {
    00070       pbuf_free(buf->p);
    00071       buf->p = buf->ptr = NULL;
    00072     }
    00073     memp_freep(MEMP_NETBUF, buf);
    00074   }
    00075 }
    00076 /*-----------------------------------------------------------------------------------*/
    00077 void *
    00078 netbuf_alloc(struct netbuf *buf, uInt16 size)
    00079 {
    00080   /* Deallocate any previously allocated memory. */
    00081   if(buf->p != NULL) {
    00082     pbuf_free(buf->p);
    00083   }
    00084   buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
    00085   if(buf->p == NULL) {
    00086      return NULL;
    00087   }
    00088   buf->ptr = buf->p;
    00089   return buf->p->payload;
    00090 }
    00091 /*-----------------------------------------------------------------------------------*/
    00092 void
    00093 netbuf_free(struct netbuf *buf)
    00094 {
    00095   if(buf->p != NULL) {
    00096     pbuf_free(buf->p);
    00097   }
    00098   buf->p = buf->ptr = NULL;
    00099 }
    00100 /*-----------------------------------------------------------------------------------*/
    00101 void
    00102 netbuf_ref(struct netbuf *buf, void *dataptr, uInt16 size)
    00103 {
    00104   if(buf->p != NULL) {
    00105     pbuf_free(buf->p);
    00106   }
    00107   buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_ROM);
    00108   buf->p->payload = dataptr;
    00109   buf->p->len = buf->p->tot_len = size;
    00110   buf->ptr = buf->p;
    00111 }
    00112 /*-----------------------------------------------------------------------------------*/
    00113 void
    00114 netbuf_chain(struct netbuf *head, struct netbuf *tail)
    00115 {
    00116   pbuf_chain(head->p, tail->p);
    00117   head->ptr = head->p;
    00118   memp_freep(MEMP_NETBUF, tail);
    00119 }
    00120 /*-----------------------------------------------------------------------------------*/
    00121 uInt16
    00122 netbuf_len(struct netbuf *buf)
    00123 {
    00124   return buf->p->tot_len;
    00125 }
    00126 /*-----------------------------------------------------------------------------------*/
    00127 err_t
    00128 netbuf_data(struct netbuf *buf, void **dataptr, uInt16 *len)
    00129 {
    00130   if(buf->ptr == NULL) {
    00131     return ERR_BUF;
    00132   }
    00133   *dataptr = buf->ptr->payload;
    00134   *len = buf->ptr->len;
    00135   return ERR_OK;
    00136 }
    00137 /*-----------------------------------------------------------------------------------*/
    00138 Int8
    00139 netbuf_next(struct netbuf *buf)
    00140 {
    00141   if(buf->ptr->next == NULL) {
    00142     return -1;
    00143   }
    00144   buf->ptr = buf->ptr->next;
    00145   if(buf->ptr->next == NULL) {
    00146     return 1;
    00147   }
    00148   return 0;
    00149 }
    00150 /*-----------------------------------------------------------------------------------*/
    00151 void
    00152 netbuf_first(struct netbuf *buf)
    00153 {
    00154   buf->ptr = buf->p;
    00155 }
    00156 /*-----------------------------------------------------------------------------------*/
    00157 void
    00158 netbuf_copy_partial(struct netbuf *buf, void *dataptr, uInt16 len, uInt16 offset)
    00159 {
    00160   struct pbuf *p;
    00161   uInt16 i, left;
    00162
    00163   left = 0;
    00164
    00165   if(buf == NULL) {
    00166     return;
    00167   }
    00168
    00169   /* This implementation is bad. It should use bcopy
    00170      instead. */
    00171   for(p = buf->p; left < len && p != NULL; p = p->next) {
    00172     if(offset != 0 && offset >= p->len) {
    00173       offset -= p->len;
    00174     } else {
    00175       for(i = offset; i < p->len; ++i) {
    00176         ((char *)dataptr)[left] = ((char *)p->payload)[i];
    00177         if(++left >= len) {
    00178           return;
    00179         }
    00180       }
    00181     }
    00182   }
    00183 }
    00184 /*-----------------------------------------------------------------------------------*/
    00185 void
    00186 netbuf_copy(struct netbuf *buf, void *dataptr, uInt16 len)
    00187 {
    00188   netbuf_copy_partial(buf, dataptr, len, 0);
    00189 }
    00190 /*-----------------------------------------------------------------------------------*/
    00191 struct ip_addr *
    00192 netbuf_fromaddr(struct netbuf *buf)
    00193 {
    00194   return buf->fromaddr;
    00195 }
    00196 /*-----------------------------------------------------------------------------------*/
    00197 uInt16
    00198 netbuf_fromport(struct netbuf *buf)
    00199 {
    00200   return buf->fromport;
    00201 }
    00202 /*-----------------------------------------------------------------------------------*/
    00203 struct
    00204 netconn *netconn_new(enum netconn_type t)
    00205 {
    00206   struct netconn *conn;
    00207
    00208   conn = memp_mallocp(MEMP_NETCONN);
    00209   if(conn == NULL) {
    00210     return NULL;
    00211   }
    00212   conn->type = t;
    00213   conn->pcb.tcp = NULL;
    00214
    00215   if((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) {
    00216     memp_freep(MEMP_NETCONN, conn);
    00217     return NULL;
    00218   }
    00219   conn->recvmbox = SYS_MBOX_NULL;
    00220   conn->acceptmbox = SYS_MBOX_NULL;
    00221   conn->sem = SYS_SEM_NULL;
    00222   conn->state = NETCONN_NONE;
    00223   return conn;
    00224 }
    00225 /*-----------------------------------------------------------------------------------*/
    00226 err_t
    00227 netconn_delete(struct netconn *conn)
    00228 {
    00229   struct api_msg *msg;
    00230   void *mem;
    00231
    00232   if(conn == NULL) {
    00233     return ERR_OK;
    00234   }
    00235
    00236   if((msg = memp_mallocp(MEMP_API_MSG)) == NULL) {
    00237     return ERR_MEM;
    00238   }
    00239
    00240   msg->type = API_MSG_DELCONN;
    00241   msg->msg.conn = conn;
    00242   api_msg_post(msg);
    00243   sys_mbox_fetch(conn->mbox, NULL);
    00244   memp_freep(MEMP_API_MSG, msg);
    00245
    00246   /* Drain the recvmbox. */
    00247   if(conn->recvmbox != SYS_MBOX_NULL) {
    00248     while(sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != 0) {
    00249       if(conn->type == NETCONN_TCP) {
    00250         pbuf_free((struct pbuf *)mem);
    00251       } else {
    00252         netbuf_delete((struct netbuf *)mem);
    00253       }
    00254     }
    00255     sys_mbox_free(conn->recvmbox);
    00256     conn->recvmbox = SYS_MBOX_NULL;
    00257   }
    00258
    00259
    00260   /* Drain the acceptmbox. */
    00261   if(conn->acceptmbox != SYS_MBOX_NULL) {
    00262     while(sys_arch_mbox_fetch(conn->acceptmbox, &mem, 1) != 0) {
    00263       netconn_delete((struct netconn *)mem);
    00264     }
    00265
    00266     sys_mbox_free(conn->acceptmbox);
    00267     conn->acceptmbox = SYS_MBOX_NULL;
    00268   }
    00269
    00270   sys_mbox_free(conn->mbox);
    00271   conn->mbox = SYS_MBOX_NULL;
    00272   if(conn->sem != SYS_SEM_NULL) {
    00273     sys_sem_free(conn->sem);
    00274   }
    00275   /*  conn->sem = SYS_SEM_NULL;*/
    00276   memp_free(MEMP_NETCONN, conn);
    00277   return ERR_OK;
    00278 }
    00279 /*-----------------------------------------------------------------------------------*/
    00280 enum netconn_type
    00281 netconn_type(struct netconn *conn)
    00282 {
    00283   return conn->type;
    00284 }
    00285 /*-----------------------------------------------------------------------------------*/
    00286 err_t
    00287 netconn_peer(struct netconn *conn, struct ip_addr **addr,
    00288              uInt16 *port)
    00289 {
    00290   switch(conn->type) {
    00291   case NETCONN_UDPLITE:
    00292   case NETCONN_UDPNOCHKSUM:
    00293   case NETCONN_UDP:
    00294     *addr = &(conn->pcb.udp->remote_ip);
    00295     *port = conn->pcb.udp->remote_port;
    00296     break;
    00297   case NETCONN_TCP:
    00298     *addr = &(conn->pcb.tcp->remote_ip);
    00299     *port = conn->pcb.tcp->remote_port;
    00300     break;
    00301   }
    00302   return (conn->err = ERR_OK);
    00303 }
    00304 /*-----------------------------------------------------------------------------------*/
    00305 err_t
    00306 netconn_addr(struct netconn *conn, struct ip_addr **addr,
    00307              uInt16 *port)
    00308 {
    00309   switch(conn->type) {
    00310   case NETCONN_UDPLITE:
    00311   case NETCONN_UDPNOCHKSUM:
    00312   case NETCONN_UDP:
    00313     *addr = &(conn->pcb.udp->local_ip);
    00314     *port = conn->pcb.udp->local_port;
    00315     break;
    00316   case NETCONN_TCP:
    00317     *addr = &(conn->pcb.tcp->local_ip);
    00318     *port = conn->pcb.tcp->local_port;
    00319     break;
    00320   }
    00321   return (conn->err = ERR_OK);
    00322 }
    00323 /*-----------------------------------------------------------------------------------*/
    00324 err_t
    00325 netconn_bind(struct netconn *conn, struct ip_addr *addr,
    00326             uInt16 port)
    00327 {
    00328   struct api_msg *msg;
    00329
    00330   if(conn == NULL) {
    00331     return ERR_VAL;
    00332   }
    00333
    00334   if(conn->type != NETCONN_TCP &&
    00335      conn->recvmbox == SYS_MBOX_NULL) {
    00336     if((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
    00337       return ERR_MEM;
    00338     }
    00339   }
    00340
    00341   if((msg = memp_mallocp(MEMP_API_MSG)) == NULL) {
    00342     return (conn->err = ERR_MEM);
    00343   }
    00344   msg->type = API_MSG_BIND;
    00345   msg->msg.conn = conn;
    00346   msg->msg.msg.bc.ipaddr = addr;
    00347   msg->msg.msg.bc.port = port;
    00348   api_msg_post(msg);
    00349   sys_mbox_fetch(conn->mbox, NULL);
    00350   memp_freep(MEMP_API_MSG, msg);
    00351   return conn->err;
    00352 }
    00353 /*-----------------------------------------------------------------------------------*/
    00354 err_t
    00355 netconn_connect(struct netconn *conn, struct ip_addr *addr,
    00356                    uInt16 port)
    00357 {
    00358   struct api_msg *msg;
    00359
    00360   if(conn == NULL) {
    00361     return ERR_VAL;
    00362   }
    00363
    00364
    00365   if(conn->recvmbox == SYS_MBOX_NULL) {
    00366     if((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {
    00367       return ERR_MEM;
    00368     }
    00369   }
    00370
    00371   if((msg = memp_mallocp(MEMP_API_MSG)) == NULL) {
    00372     return ERR_MEM;
    00373   }
    00374   msg->type = API_MSG_CONNECT;
    00375   msg->msg.conn = conn;
    00376   msg->msg.msg.bc.ipaddr = addr;
    00377   msg->msg.msg.bc.port = port;
    00378   kprintf("1");
    00379   api_msg_post(msg);
    00380   kprintf("2: [0x%X]",conn->mbox);
    00381   sys_mbox_fetch(conn->mbox, NULL);
    00382   kprintf("3");
    00383   memp_freep(MEMP_API_MSG, msg);
    00384   kprintf("4");
    00385   return conn->err;
    00386 }
    00387 /*-----------------------------------------------------------------------------------*/
    00388 err_t
    00389 netconn_listen(struct netconn *conn)
    00390 {
    00391   struct api_msg *msg;
    00392
    00393   if(conn == NULL) {
    00394     return ERR_VAL;
    00395   }
    00396
    00397   if(conn->acceptmbox == SYS_MBOX_NULL) {
    00398     conn->acceptmbox = sys_mbox_new();
    00399     if(conn->acceptmbox == SYS_MBOX_NULL) {
    00400       return ERR_MEM;
    00401     }
    00402   }
    00403
    00404   if((msg = memp_mallocp(MEMP_API_MSG)) == NULL) {
    00405     return (conn->err = ERR_MEM);
    00406   }
    00407   msg->type = API_MSG_LISTEN;
    00408   msg->msg.conn = conn;
    00409   api_msg_post(msg);
    00410   sys_mbox_fetch(conn->mbox, NULL);
    00411   memp_freep(MEMP_API_MSG, msg);
    00412   return conn->err;
    00413 }
    00414 /*-----------------------------------------------------------------------------------*/
    00415 struct netconn *
    00416 netconn_accept(struct netconn *conn)
    00417 {
    00418   struct netconn *newconn;
    00419
    00420   if(conn == NULL) {
    00421     return NULL;
    00422   }
    00423
    00424   sys_mbox_fetch(conn->acceptmbox, (void **)&newconn);
    00425
    00426   return newconn;
    00427 }
    00428 /*-----------------------------------------------------------------------------------*/
    00429 struct netbuf *
    00430 netconn_recv(struct netconn *conn)
    00431 {
    00432   struct api_msg *msg;
    00433   struct netbuf *buf;
    00434   struct pbuf *p;
    00435
    00436   if(conn == NULL) {
    00437     return NULL;
    00438   }
    00439
    00440   if(conn->recvmbox == SYS_MBOX_NULL) {
    00441     conn->err = ERR_CONN;
    00442     return NULL;
    00443   }
    00444
    00445   if(conn->err != ERR_OK) {
    00446     return NULL;
    00447   }
    00448
    00449   if(conn->type == NETCONN_TCP) {
    00450     if(conn->pcb.tcp->state == LISTEN) {
    00451       conn->err = ERR_CONN;
    00452       return NULL;
    00453     }
    00454
    00455
    00456     buf = memp_mallocp(MEMP_NETBUF);
    00457
    00458     if(buf == NULL) {
    00459       conn->err = ERR_MEM;
    00460       return NULL;
    00461     }
    00462
    00463     sys_mbox_fetch(conn->recvmbox, (void **)&p);
    00464
    00465     /* If we are closed, we indicate that we no longer wish to recieve
    00466        data by setting conn->recvmbox to SYS_MBOX_NULL. */
    00467     if(p == NULL) {
    00468       memp_freep(MEMP_NETBUF, buf);
    00469       sys_mbox_free(conn->recvmbox);
    00470       conn->recvmbox = SYS_MBOX_NULL;
    00471       return NULL;
    00472     }
    00473
    00474     buf->p = p;
    00475     buf->ptr = p;
    00476     buf->fromport = 0;
    00477     buf->fromaddr = NULL;
    00478
    00479     /* Let the stack know that we have taken the data. */
    00480     if((msg = memp_mallocp(MEMP_API_MSG)) == NULL) {
    00481       conn->err = ERR_MEM;
    00482       return buf;
    00483     }
    00484     msg->type = API_MSG_RECV;
    00485     msg->msg.conn = conn;
    00486     if(buf != NULL) {
    00487       msg->msg.msg.len = buf->p->tot_len;
    00488     } else {
    00489       msg->msg.msg.len = 1;
    00490     }
    00491     api_msg_post(msg);
    00492
    00493     sys_mbox_fetch(conn->mbox, NULL);
    00494     memp_freep(MEMP_API_MSG, msg);
    00495   } else {
    00496     sys_mbox_fetch(conn->recvmbox, (void **)&buf);
    00497   }
    00498
    00499
    00500
    00501
    00502   DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", buf, conn->err));
    00503
    00504
    00505   return buf;
    00506 }
    00507 /*-----------------------------------------------------------------------------------*/
    00508 err_t
    00509 netconn_send(struct netconn *conn, struct netbuf *buf)
    00510 {
    00511   struct api_msg *msg;
    00512
    00513   if(conn == NULL) {
    00514     return ERR_VAL;
    00515   }
    00516
    00517   if(conn->err != ERR_OK) {
    00518     return conn->err;
    00519   }
    00520
    00521   if((msg = memp_mallocp(MEMP_API_MSG)) == NULL) {
    00522     return (conn->err = ERR_MEM);
    00523   }
    00524
    00525   DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
    00526   msg->type = API_MSG_SEND;
    00527   msg->msg.conn = conn;
    00528   msg->msg.msg.p = buf->p;
    00529   api_msg_post(msg);
    00530
    00531   sys_mbox_fetch(conn->mbox, NULL);
    00532   memp_freep(MEMP_API_MSG, msg);
    00533   return conn->err;
    00534 }
    00535 /*-----------------------------------------------------------------------------------*/
    00536 err_t
    00537 netconn_write(struct netconn *conn, void *dataptr, uInt16 size, uInt8 copy)
    00538 {
    00539   struct api_msg *msg;
    00540   uInt16 len;
    00541
    00542   if(conn == NULL) {
    00543     return ERR_VAL;
    00544   }
    00545
    00546   if(conn->err != ERR_OK) {
    00547     return conn->err;
    00548   }
    00549
    00550   if(conn->sem == SYS_SEM_NULL) {
    00551     conn->sem = sys_sem_new(0);
    00552     if(conn->sem == SYS_SEM_NULL) {
    00553       return ERR_MEM;
    00554     }
    00555   }
    00556
    00557   if((msg = memp_mallocp(MEMP_API_MSG)) == NULL) {
    00558     return (conn->err = ERR_MEM);
    00559   }
    00560   msg->type = API_MSG_WRITE;
    00561   msg->msg.conn = conn;
    00562
    00563
    00564   conn->state = NETCONN_WRITE;
    00565   while(conn->err == ERR_OK && size > 0) {
    00566     msg->msg.msg.w.dataptr = dataptr;
    00567     msg->msg.msg.w.copy = copy;
    00568
    00569     if(conn->type == NETCONN_TCP) {
    00570       if(tcp_sndbuf(conn->pcb.tcp) == 0) {
    00571         sys_sem_wait(conn->sem);
    00572         if(conn->err != ERR_OK) {
    00573           goto ret;
    00574         }
    00575       }
    00576       if(size > tcp_sndbuf(conn->pcb.tcp)) {
    00577         /* We cannot send more than one send buffer's worth of data at a
    00578            time. */
    00579         len = tcp_sndbuf(conn->pcb.tcp);
    00580       } else {
    00581         len = size;
    00582       }
    00583     } else {
    00584       len = size;
    00585     }
    00586
    00587     DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy));
    00588     msg->msg.msg.w.len = len;
    00589     api_msg_post(msg);
    00590     sys_mbox_fetch(conn->mbox, NULL);
    00591     if(conn->err == ERR_OK) {
    00592       dataptr = (void *)((char *)dataptr + len);
    00593       size -= len;
    00594     } else if(conn->err == ERR_MEM) {
    00595       conn->err = ERR_OK;
    00596       sys_sem_wait(conn->sem);
    00597     } else {
    00598       goto ret;
    00599     }
    00600   }
    00601  ret:
    00602   memp_freep(MEMP_API_MSG, msg);
    00603   conn->state = NETCONN_NONE;
    00604   if(conn->sem != SYS_SEM_NULL) {
    00605     sys_sem_free(conn->sem);
    00606     conn->sem = SYS_SEM_NULL;
    00607   }
    00608   return conn->err;
    00609 }
    00610 /*-----------------------------------------------------------------------------------*/
    00611 err_t
    00612 netconn_close(struct netconn *conn)
    00613 {
    00614   struct api_msg *msg;
    00615
    00616   if(conn == NULL) {
    00617     return ERR_VAL;
    00618   }
    00619   if((msg = memp_mallocp(MEMP_API_MSG)) == NULL) {
    00620     return (conn->err = ERR_MEM);
    00621   }
    00622
    00623   conn->state = NETCONN_CLOSE;
    00624  again:
    00625   msg->type = API_MSG_CLOSE;
    00626   msg->msg.conn = conn;
    00627   api_msg_post(msg);
    00628   sys_mbox_fetch(conn->mbox, NULL);
    00629   if(conn->err == ERR_MEM &&
    00630      conn->sem != SYS_SEM_NULL) {
    00631     sys_sem_wait(conn->sem);
    00632     goto again;
    00633   }
    00634   conn->state = NETCONN_NONE;
    00635   memp_freep(MEMP_API_MSG, msg);
    00636   return conn->err;
    00637 }
    00638 /*-----------------------------------------------------------------------------------*/
    00639 err_t
    00640 netconn_err(struct netconn *conn)
    00641 {
    00642   return conn->err;
    00643 }
    00644 /*-----------------------------------------------------------------------------------*/
    00645
    00646
    00647
    00648