GainSpan Wi-Fi library see: http://mbed.org/users/gsfan/notebook/gainspan_wifi/

Fork of GSwifi_old by gs fan

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GSwifi_httpd.cpp Source File

GSwifi_httpd.cpp

00001 #include "dbg.h"
00002 #include "mbed.h"
00003 #include "GSwifi.h"
00004 #include "sha1.h"
00005 #include <string.h>
00006 
00007 #ifdef GS_USE_HTTPD
00008 
00009 #define MIMETABLE_NUM 8
00010 struct {
00011     char ext[6];
00012     char type[24];
00013 } mimetable[MIMETABLE_NUM] = {
00014     {".txt", "text/plain"},
00015     {".html", "text/html"},
00016     {".htm", "text/html"},
00017     {".css", "text/css"},
00018     {".js", "application/javascript"},
00019     {".jpg", "image/jpeg"},
00020     {".png", "image/png"},
00021     {".gif", "image/gif"},
00022 };
00023 
00024 int GSwifi::httpd (int port) {
00025     int i;
00026     char cmd[GS_CMD_SIZE];
00027 
00028     if (! _connect || _status != GSSTAT_READY) return -1;
00029 
00030     memset(&_httpd, 0, sizeof(_httpd));
00031     for (i = 0; i < 16; i ++) {
00032         _httpd[i].mode = GSHTTPDMODE_REQUEST;
00033     }
00034     _handler_count = 0;
00035 
00036     sprintf(cmd, "AT+NSTCP=%d", port);
00037     if (command(cmd, GSRES_CONNECT)) return -1;
00038 
00039     newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, NULL);
00040 /*
00041 //    newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, &GSwifi::poll_httpd);
00042 //    newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, reinterpret_cast<onGsReceiveFunc>(&GSwifi::poll_httpd));
00043     void (GSwifi::*f1)(int,int) = &GSwifi::poll_httpd;
00044     onGsReceiveFunc f2 = reinterpret_cast<onGsReceiveFunc>(f1);
00045     newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, f2);
00046 */
00047     return _cid;
00048 }
00049 
00050 void GSwifi::poll_httpd (int cid, int len) {
00051     int i, j, flg = 0;
00052     char c;
00053 
00054     if (len == 0) {
00055         // start request
00056         _httpd[cid].mode = GSHTTPDMODE_REQUEST;
00057         _httpd[cid].len = 0;
00058         _httpd[cid].keepalive = 0;
00059 #ifdef GS_USE_WEBSOCKET
00060         _httpd[cid].websocket = 0;
00061 #endif
00062         return;
00063     }
00064 
00065 #ifdef GS_USE_WEBSOCKET
00066     if (_httpd[cid].mode >= GSHTTPDMODE_WEBSOCKET) {
00067         poll_websocket(cid, len);
00068         return;
00069     }
00070 #endif
00071 
00072   while (_gs_sock[cid].connect && _gs_sock[cid].data->use()) {
00073     flg = 0;
00074     if (_httpd[cid].buf == NULL) {
00075         _httpd[cid].buf = new char[HTTPD_BUF_SIZE];
00076     }
00077     // get 1 line
00078     for (j = 0; j < len; j ++) {
00079         _gs_sock[cid].data->get(&c);
00080         if (c == '\r') continue;
00081         if (c == '\n' && _httpd[cid].mode != GSHTTPDMODE_BODY) break;
00082         
00083         if (_httpd[cid].len < HTTPD_BUF_SIZE - 1) {
00084             _httpd[cid].buf[_httpd[cid].len] = c; 
00085         }
00086         _httpd[cid].len ++;
00087         if (_httpd[cid].mode == GSHTTPDMODE_BODY && _httpd[cid].len >= _httpd[cid].length) break; // end of body
00088     }
00089     if (j >= len) return; // continue
00090     if (_httpd[cid].len < HTTPD_BUF_SIZE) {
00091         _httpd[cid].buf[_httpd[cid].len] = 0;
00092         DBG("httpd %d: %d %s (%d)\r\n", cid, _httpd[cid].mode, _httpd[cid].buf, _httpd[cid].len);
00093     }
00094 
00095     // parse
00096     switch (_httpd[cid].mode) {
00097     case GSHTTPDMODE_REQUEST:
00098         if (strnicmp(_httpd[cid].buf, "GET ", 4) == 0) {
00099             _httpd[cid].type = GSPROT_HTTPGET;
00100             j = 4;
00101         } else
00102         if (strnicmp(_httpd[cid].buf, "POST ", 5) == 0) {
00103             _httpd[cid].type = GSPROT_HTTPPOST;
00104             j = 5;
00105         } else {
00106             _httpd[cid].mode = GSHTTPDMODE_ERROR;
00107             break;
00108         }
00109 
00110         // get uri
00111         for (i = j; i < _httpd[cid].len; i ++) {
00112             if (_httpd[cid].buf[i] == ' ') break;
00113         }
00114         i = i - j;
00115         if (i) {
00116             if (_httpd[cid].uri == NULL) {
00117                 _httpd[cid].uri = new char[HTTPD_URI_SIZE];
00118             }
00119             strncpy(_httpd[cid].uri, &_httpd[cid].buf[j], i);
00120             _httpd[cid].uri[i] = 0;
00121         }
00122         _httpd[cid].mode = GSHTTPDMODE_HEAD;
00123         _httpd[cid].length = 0;
00124         DBG("uri: %s\r\n", _httpd[cid].uri);
00125         break;
00126         
00127     case GSHTTPDMODE_HEAD:
00128         if (_httpd[cid].len == 0) {
00129             // blank line (end of header)
00130             _httpd[cid].mode = GSHTTPDMODE_BODY;
00131             if (_httpd[cid].length == 0) flg = 1; // no body
00132 #ifdef GS_USE_WEBSOCKET
00133             if (_httpd[cid].websocket && _httpd[cid].websocket_key) {
00134                 // enter websocket
00135                 _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET;
00136                 _httpd[cid].len = 0;
00137                 flg = 1;
00138             }
00139 #endif
00140         } else
00141         if (strnicmp(_httpd[cid].buf, "Content-Length: ", 16) == 0) {
00142             _httpd[cid].length = atoi(&_httpd[cid].buf[16]);
00143         } else
00144         if (strnicmp(_httpd[cid].buf, "Connection: Keep-Alive", 22) == 0) {
00145             if (! _httpd[cid].keepalive) {
00146                 _httpd[cid].keepalive = HTTPD_KEEPALIVE;
00147             }
00148 #ifdef GS_USE_WEBSOCKET
00149         } else
00150         if (strnicmp(_httpd[cid].buf, "Upgrade: websocket", 18) == 0) {
00151             if (! _httpd[cid].websocket) _httpd[cid].websocket = 1;
00152         } else
00153         if (strnicmp(_httpd[cid].buf, "Sec-WebSocket-Version: ", 23) == 0) {
00154             _httpd[cid].websocket = atoi(&_httpd[cid].buf[23]);
00155         } else
00156         if (strnicmp(_httpd[cid].buf, "Sec-WebSocket-Key: ", 19) == 0) {
00157             if (_httpd[cid].websocket_key == NULL) {
00158                 _httpd[cid].websocket_key = new char[30];
00159             }
00160             strncpy(_httpd[cid].websocket_key, &_httpd[cid].buf[19], 30);
00161 #endif
00162         }
00163         break;
00164 
00165     case GSHTTPDMODE_BODY:
00166         if (_httpd[cid].len >= _httpd[cid].length) {
00167             DBG("body: %s\r\n", _httpd[cid].buf);
00168             flg = 1;
00169         }
00170         break;
00171 
00172     }
00173 
00174 #ifdef GS_USE_WEBSOCKET
00175     if (flg && _httpd[cid].mode == GSHTTPDMODE_WEBSOCKET) {
00176         // websocket
00177         _httpd[cid].host = _gs_sock[cid].host;
00178         j = strlen(_handler[i].uri);
00179         _httpd[cid].file = &_httpd[cid].uri[j];
00180         _httpd[cid].query = NULL;
00181 
00182         send_websocket_accept(cid);
00183         break; // exit while
00184 
00185     } else
00186 #endif
00187     if (flg) {
00188         // http request
00189         _httpd[cid].buf[_httpd[cid].len] = 0;
00190 
00191         i = get_handler(_httpd[cid].uri);
00192         if (i >= 0) {
00193             _httpd[cid].host = _gs_sock[cid].host;
00194             j = strlen(_handler[i].uri);
00195             _httpd[cid].file = &_httpd[cid].uri[j];
00196             _httpd[cid].query = NULL;
00197             for (; j < strlen(_httpd[cid].uri); j ++) {
00198                 if (_httpd[cid].uri[j] == '?') {
00199                     // query string
00200                     _httpd[cid].uri[j] = 0;
00201                     _httpd[cid].query = &_httpd[cid].uri[j + 1];
00202                     break;
00203                 }
00204             }
00205 
00206             if (_handler[i].dir) {
00207                 // file
00208                 httpd_request(cid, &_httpd[cid], _handler[i].dir);
00209                 flg = 1;
00210             } else
00211             if (_handler[i].onHttpCgi) {
00212                 // cgi
00213                 _handler[i].onHttpCgi(cid, &_httpd[cid]);
00214                 _httpd[cid].keepalive = 0;
00215                 LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
00216                 LOG("%s %s %d 200 -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length);
00217                 flg = 1;
00218             }
00219         } else {
00220             // not found
00221             send_httpd_error(cid, 403);
00222         }
00223         
00224         if (_httpd[cid].keepalive) {
00225             _httpd[cid].mode = GSHTTPDMODE_REQUEST;
00226             _httpd[cid].len = 0;
00227             _httpd[cid].length = 0;
00228             _httpd[cid].keepalive --;
00229         } else {
00230             close(cid);
00231         }
00232     }
00233 
00234     if (_httpd[cid].mode == GSHTTPDMODE_ERROR) {
00235         send_httpd_error(cid, 400);
00236     }
00237 
00238     _httpd[cid].len = 0;
00239   } // while
00240 }
00241 
00242 int GSwifi::get_handler (char *uri) {
00243     int i, j;
00244 
00245     for (i = 0; i < _handler_count; i ++) {
00246         j = strlen(_handler[i].uri);
00247         if (strncmp(uri, _handler[i].uri, j) == NULL) {
00248             // found
00249             return i;
00250         }
00251     }
00252     return -1;
00253 }
00254 
00255 int GSwifi::httpd_request (int cid, GS_httpd *gshttpd, char *dir) {
00256     FILE *fp;
00257     int i, len;
00258     char buf[HTTPD_BUF_SIZE];
00259     char file[HTTPD_URI_SIZE];
00260 
00261     strcpy(file, dir);
00262     strcat(file, gshttpd->file);
00263     if (file[strlen(file) - 1] == '/') {
00264         strcat(file, "index.html");
00265     }
00266     DBG("file: %s\r\n", file);
00267     
00268     fp = fopen(file, "r");
00269     if (fp) {
00270         send(cid, "HTTP/1.1 200 OK\r\n", 17);
00271         {
00272             // file size
00273             i = ftell(fp);
00274             fseek(fp, 0, SEEK_END);
00275             len = ftell(fp);
00276             fseek(fp, i, SEEK_SET);
00277         }
00278         sprintf(buf, "Content-Length: %d\r\n", len);
00279         send(cid, buf, strlen(buf));
00280         sprintf(buf, "Content-Type: %s\r\n", mimetype(file));
00281         send(cid, buf, strlen(buf));
00282         if (gshttpd->keepalive) {
00283             strcpy(buf, "Connection: Keep-Alive\r\n");
00284         } else {
00285             strcpy(buf, "Connection: close\r\n");
00286         }
00287         send(cid, buf, strlen(buf));
00288         strcpy(buf, "Server: GSwifi httpd\r\n");
00289         send(cid, buf, strlen(buf));
00290         send(cid, "\r\n", 2);
00291 
00292         for (;;) {
00293             i = fread(buf, sizeof(char), sizeof(buf), fp);
00294             if (i <= 0) break;
00295             if (! _gs_sock[cid].connect) break;
00296             send(cid, buf, i);
00297 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00298             if (feof(fp)) break;
00299 #endif
00300         }
00301         fclose(fp);
00302         LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
00303         LOG("%s %s %d 200 %d\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, len);
00304         return 0;
00305     }
00306 
00307     send_httpd_error(cid, 404);
00308     return -1;
00309 }
00310 
00311 char *GSwifi::mimetype (char *file) {
00312     int i, j;
00313 
00314     DBG("<%s>\r\n", file);
00315     for (i = 0; i < MIMETABLE_NUM; i ++) {
00316         j = strlen(mimetable[i].ext);
00317         if (strnicmp(&file[strlen(file) - j], mimetable[i].ext, j) == NULL) {
00318             return mimetable[i].type;
00319         }
00320     }
00321     return mimetable[0].type;
00322 }
00323 
00324 int GSwifi::strnicmp (char *p1, char *p2, int n) {
00325     int i, r;
00326     char c1, c2;
00327     
00328     for (i = 0; i < n; i ++) {
00329         c1 = (p1[i] >= 'a' && p1[i] <= 'z') ? p1[i] - ('a' - 'A'): p1[i];
00330         c2 = (p2[i] >= 'a' && p2[i] <= 'z') ? p2[i] - ('a' - 'A'): p2[i];
00331         r = c1 - c2;
00332         if (r) break;
00333     }
00334     return r;
00335 }
00336 
00337 void GSwifi::send_httpd_error (int cid, int err) {
00338     char buf[100], msg[30];
00339     
00340     switch (err) {
00341     case 400:
00342         strcpy(msg, "Bad Request");
00343         break;
00344     case 403:
00345         strcpy(msg, "Forbidden");
00346         break;
00347     case 404:
00348         strcpy(msg, "Not Found");
00349         break;
00350     case 500:
00351     default:
00352         strcpy(msg, "Internal Server Error");
00353         break;
00354     }
00355     DBG("httpd error: %d %d %s\r\n", cid, err, msg);
00356     
00357     sprintf(buf, "HTTP/1.1 %d %s\r\n", err, msg);
00358     send(cid, buf, strlen(buf));
00359     strcpy(buf, "Content-Type: text/html\r\n");
00360     send(cid, buf, strlen(buf));
00361     send(cid, "\r\n", 2);
00362 
00363     sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg);
00364     send(cid, buf, strlen(buf));
00365     sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg);
00366     send(cid, buf, strlen(buf));
00367     close(cid);
00368     LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
00369     LOG("%s %s %d %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err);
00370 }
00371 
00372 int GSwifi::attach_httpd (const char *uri, const char *dir) {
00373     if (_handler_count < HTTPD_HANDLE) {
00374         _handler[_handler_count].uri = new char[strlen(uri) + 1];
00375         strcpy(_handler[_handler_count].uri, uri);
00376         _handler[_handler_count].dir = new char[strlen(dir) + 1];
00377         strcpy(_handler[_handler_count].dir, dir);
00378         _handler[_handler_count].onHttpCgi = NULL;
00379         _handler_count ++;
00380         return 0;
00381     } else {
00382         return -1;
00383     }
00384 }
00385 
00386 int GSwifi::attach_httpd (const char *uri, onHttpdCgiFunc ponHttpCgi) {
00387     if (_handler_count < HTTPD_HANDLE) {
00388         _handler[_handler_count].uri = new char[strlen(uri) + 1];
00389         strcpy(_handler[_handler_count].uri, uri);
00390         _handler[_handler_count].dir = NULL;
00391         _handler[_handler_count].onHttpCgi = ponHttpCgi;
00392         _handler_count ++;
00393         return 0;
00394     } else {
00395         return -1;
00396     }
00397 }
00398 
00399 #ifdef GS_USE_WEBSOCKET
00400 void GSwifi::poll_websocket (int cid, int len) {
00401     int i, j, flg;
00402     unsigned char c;
00403 
00404     while (_gs_sock[cid].connect && _gs_sock[cid].data->use()) {
00405         flg = 0;
00406         // get 1 line
00407         for (j = 0; j < len; j ++) {
00408             _gs_sock[cid].data->get((char*)&c);
00409 //            DBG("_%c", c);
00410 
00411             switch (_httpd[cid].mode) {
00412             case GSHTTPDMODE_WEBSOCKET:
00413                 if (_httpd[cid].len == 0) {
00414                     _httpd[cid].type = c & 0x0f;
00415                     _httpd[cid].websocket_flg = c << 8;
00416                     _httpd[cid].len ++;
00417                 } else
00418                 if (_httpd[cid].len == 1) {
00419                     _httpd[cid].websocket_flg |= c;
00420                     _httpd[cid].length = c & 0x7f;
00421                     _httpd[cid].len ++;
00422                     if (_httpd[cid].length < 126) {
00423                         _httpd[cid].len = 0;
00424                         if (_httpd[cid].websocket_flg & 0x0080) {
00425                             _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_MASK;
00426                         } else {
00427                             _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY;
00428                         }
00429                         DBG("ws length %d\r\n", _httpd[cid].length);
00430                     }
00431                 } else {
00432                     // length 16bit,64bit
00433                     if (_httpd[cid].len == 2) {
00434                         _httpd[cid].length = c;
00435                         _httpd[cid].len ++;
00436                     } else
00437                     if (_httpd[cid].len < 9 && (_httpd[cid].websocket_flg & 0x7f) == 127) {
00438                         // 64bit
00439                         _httpd[cid].length = (_httpd[cid].length << 8) | c;
00440                         _httpd[cid].len ++;
00441                     } else {
00442                         _httpd[cid].length = (_httpd[cid].length << 8) | c;
00443                         _httpd[cid].len = 0;
00444                         if (_httpd[cid].websocket_flg & 0x0080) {
00445                             _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_MASK;
00446                         } else {
00447                             _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY;
00448                         }
00449                         DBG("ws length2 %d\r\n", _httpd[cid].length);
00450                     }
00451                 }
00452                 break;
00453 
00454             case GSHTTPDMODE_WEBSOCKET_MASK:
00455                 _httpd[cid].websocket_mask[_httpd[cid].len] = c;
00456                 _httpd[cid].len ++;
00457                 if (_httpd[cid].len >= 4) {
00458                     _httpd[cid].len = 0;
00459                     _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY;
00460                     DBG("ws mask\r\n");
00461                 }
00462                 break;
00463 
00464             case GSHTTPDMODE_WEBSOCKET_BODY:
00465                 if (_httpd[cid].len < HTTPD_BUF_SIZE - 1) {
00466                     if (_httpd[cid].websocket_flg & 0x0080) {
00467                         _httpd[cid].buf[_httpd[cid].len] = c ^ _httpd[cid].websocket_mask[_httpd[cid].len & 0x03]; 
00468                     } else {
00469                         _httpd[cid].buf[_httpd[cid].len] = c; 
00470                     }
00471                     _httpd[cid].len ++;
00472                 }
00473                 break;
00474             }
00475 
00476             if (_httpd[cid].mode == GSHTTPDMODE_WEBSOCKET_BODY && _httpd[cid].len >= _httpd[cid].length) {
00477                 flg = 1;
00478                 break;
00479             }
00480         }
00481         if (j >= len) return; // continue
00482         if (_httpd[cid].len < HTTPD_BUF_SIZE) {
00483             _httpd[cid].buf[_httpd[cid].len] = 0;
00484             DBG("websocket %d: (%d)\r\n", cid, _httpd[cid].len);
00485         }
00486 
00487     if (flg) {
00488         // websocket request
00489       DBG("ws type %d\r\n", _httpd[cid].type);
00490       switch (_httpd[cid].type) {
00491       case 0x00: // continuation
00492       case 0x01: // text
00493       case 0x02: // binary
00494         i = get_handler(_httpd[cid].uri);
00495         if (i >= 0) {
00496             if (_handler[i].onHttpCgi) {
00497                 // cgi
00498                 _handler[i].onHttpCgi(cid, &_httpd[cid]);
00499                 LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
00500                 LOG("%s %s %d 200 -\r\n", "WEBSOCKET", _httpd[cid].uri, _httpd[cid].length);
00501                 flg = 1;
00502             }
00503         }
00504         break;
00505 
00506       case 0x08: // close
00507         close(cid);
00508         break;
00509 
00510       case 0x09: // ping
00511         _gs_putc(0x8a); // pong
00512         _gs_putc(0x04);
00513         for (i = 0; i < _httpd[cid].len; i ++) {
00514             _gs_putc(_httpd[cid].buf[i]);
00515         }
00516         break;
00517 
00518       case 0x0a: // pong
00519         break;
00520       }
00521       _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET;
00522       _httpd[cid].len = 0;
00523       _httpd[cid].length = 0;
00524     }
00525     } // while
00526 }
00527 
00528 int GSwifi::send_websocket (int cid, const char *buf, int len) {
00529     int r;
00530     char tmp[10];
00531 
00532     tmp[0] = 0x81; // single, text frame
00533     if (len < 126) {
00534         tmp[1] = len;
00535         r = send(cid, tmp, 2);
00536     } else {
00537         tmp[1] = 126;
00538         tmp[2] = (len >> 8) & 0xff;
00539         tmp[3] = len & 0xff;
00540         r = send(cid, tmp, 4);
00541     }
00542     if (r == 0) {
00543         r = send(cid, buf, len);
00544     }
00545     return r;
00546 }
00547 
00548 void GSwifi::send_websocket_accept (int cid) {
00549     char buf[100], buf2[20];
00550     
00551     DBG("websocket accept: %d\r\n", cid);
00552 
00553     send(cid, "HTTP/1.1 101 Switching Protocols\r\n", 34);
00554     send(cid, "Upgrade: websocket\r\n", 20);
00555     send(cid, "Connection: Upgrade\r\n", 21);
00556 
00557     send(cid, "Sec-WebSocket-Accept: ", 22);
00558     strcpy(buf, _httpd[cid].websocket_key);
00559     strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
00560     sha1(buf, strlen(buf), buf2);
00561     base64encode(buf2, 20, buf, sizeof(buf));
00562     send(cid, buf, strlen(buf));
00563     send(cid, "\r\n", 2);
00564 //    send(cid, "Sec-WebSocket-Protocol: chat\r\n", 30);
00565     send(cid, "\r\n", 2);
00566     LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
00567     LOG("%s %s %d 101 - %s\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, buf);
00568 }
00569 #endif
00570 
00571 #endif