00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <errno.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <sys/types.h>
00030 #include <sys/stat.h>
00031 #include <signal.h>
00032
00033
00034
00035 #include "wind2unix.h"
00036
00037 #include "xsb_time.h"
00038
00039
00040 #ifdef WIN_NT
00041 #include <windows.h>
00042 #include <winuser.h>
00043 #include <winbase.h>
00044 #include <process.h>
00045 #include <tchar.h>
00046 #include <io.h>
00047 #include <stdarg.h>
00048 #include <winsock.h>
00049 #include "wsipx.h"
00050 #else
00051 #include <sys/socket.h>
00052 #include <sys/uio.h>
00053 #include <netdb.h>
00054 #include <netinet/in.h>
00055 #include <arpa/inet.h>
00056 #include <unistd.h>
00057 #include <fcntl.h>
00058 #endif
00059
00060 #include "xsb_config.h"
00061 #include "xsb_debug.h"
00062 #include "socket_xsb.h"
00063 #include "flags_xsb.h"
00064 #include "thread_xsb.h"
00065 #include "thread_defs_xsb.h"
00066 #include "timer_xsb.h"
00067
00068 #include "auxlry.h"
00069 #include "cell_xsb.h"
00070 #include "error_xsb.h"
00071 #include "cinterf.h"
00072 #include "basictypes.h"
00073
00074 #include "io_builtins_xsb.h"
00075 #include "socket_xsb.h"
00076 #include "psc_xsb.h"
00077 #include "register.h"
00078 #include "memory_xsb.h"
00079
00080 #ifdef WIN_NT
00081 typedef int socklen_t;
00082 #elif defined(SOLARIS)
00083 typedef unsigned int socklen_t;
00084 #endif
00085
00086 static u_long block_true = 1;
00087 static u_long block_false = 0;
00088
00089
00090 static xsbBool set_error_code(CTXTdeclc int ErrCode, int ErrCodeArgNumber,char *Where);
00091
00092
00093 extern FILE *fdopen(int fildes, const char *type);
00094
00095
00096 static void init_connections(CTXTdecl);
00097 static void set_sockfd(int count);
00098 static xsbBool list_sockfd(prolog_term list, fd_set *fdset, int *max_fd,
00099 int **fds, int * size);
00100 static void test_ready(CTXTdeclc prolog_term *avail_sockfds, fd_set *fdset,
00101 int *fds, int size);
00102 static void select_destroy(char *connection_name);
00103 static int getsize (prolog_term list);
00104 static int checkslot (void);
00105
00106
00107 static struct connection_t {
00108 char *connection_name;
00109 int maximum_fd;
00110 int empty_flag;
00111 int sizer;
00112 int sizew;
00113 int sizee;
00114 fd_set readset;
00115 fd_set writeset;
00116 fd_set exceptionset;
00117 int *read_fds;
00118 int *write_fds;
00119 int *exception_fds;
00120 } connections[MAXCONNECT];
00121
00122 static char *get_host_IP(char *host_name_or_IP) {
00123 struct hostent *host_struct;
00124 struct in_addr *ptr;
00125 char **listptr;
00126
00127
00128
00129 if (IS_IP_ADDR(host_name_or_IP))
00130 return(host_name_or_IP);
00131 host_struct = gethostbyname(host_name_or_IP);
00132
00133 listptr = host_struct->h_addr_list;
00134
00135 if ((ptr = (struct in_addr *) *listptr++) != NULL) {
00136 xsb_mesg(" IP address: %s", inet_ntoa(*ptr));
00137 return(inet_ntoa(*ptr));
00138 }
00139 return NULL;
00140 }
00141
00148 static int translate_domain(int xsb_domain, int *socket_domain) {
00149 if (xsb_domain == 0) {
00150 *socket_domain = AF_INET;
00151 return TRUE;
00152 } else if (xsb_domain == 1) {
00153 *socket_domain = AF_UNIX;
00154 xsb_abort("[SOCKET_REQUEST] domain AF_INET is not implemented");
00155 return TRUE;
00156 } else {
00157 xsb_abort("[SOCKET_REQUEST] Invalid domain (%d). Valid domains are: 0 - AF_INET, 1 - AF_UNIX", xsb_domain);
00158 return FALSE;
00159 }
00160 }
00161
00167 int read_select(SOCKET sock_handle, int timeout) {
00168 int rc = 0;
00169 fd_set fds;
00170 struct timeval tv;
00171
00172 FD_ZERO(&fds);
00173 FD_SET(sock_handle, &fds);
00174 tv.tv_sec = timeout;
00175 tv.tv_usec = 0;
00176
00177 if (tv.tv_sec > 0) {
00178 rc = select(sock_handle+1, &fds, NULL, NULL, &tv);
00179 if (rc < 0) {
00180 rc = 0;
00181 } else {
00182 rc = FD_ISSET(sock_handle, &fds);
00183 }
00184 } else {
00185 rc = 1;
00186 }
00187 return rc;
00188 }
00189
00195 int write_select(SOCKET sock_handle, int timeout) {
00196 int rc = 0;
00197 fd_set fds;
00198 struct timeval tv;
00199
00200 FD_ZERO(&fds);
00201 FD_SET(sock_handle, &fds);
00202 tv.tv_sec = timeout;
00203 tv.tv_usec = 0;
00204
00205 if (tv.tv_sec > 0) {
00206 rc = select(sock_handle+1, NULL, &fds, NULL, &tv);
00207 if (rc < 0) {
00208 rc = 0;
00209 } else {
00210 rc = FD_ISSET(sock_handle, &fds);
00211 }
00212 } else {
00213 rc = 1;
00214 }
00215
00216 return rc;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225 static int readmsg(SOCKET sock_handle, char **msg_buff, unsigned long *msg_len)
00226 {
00227 int actual_len;
00228
00229 char lenbuf[XSB_MSG_HEADER_LENGTH];
00230 unsigned int msglen, net_encoded_len;
00231
00232 actual_len
00233 = (long)recvfrom(sock_handle,lenbuf,XSB_MSG_HEADER_LENGTH,0,NULL,0);
00234
00235 if (SOCKET_OP_FAILED(actual_len)) return SOCK_READMSG_FAILED;
00236 if (actual_len == 0) {
00237 *msg_buff = NULL;
00238 return SOCK_READMSG_EOF;
00239 }
00240
00241 memcpy((void *) &net_encoded_len, (void *) lenbuf, XSB_MSG_HEADER_LENGTH);
00242 msglen = ntohl(net_encoded_len);
00243 *msg_len = (msglen+1)*sizeof(char);
00244
00245 if ((*msg_buff = (char *)mem_calloc(msglen+1, sizeof(char),OTHER_SPACE)) == NULL) {
00246 xsb_abort("[SOCKET_RECV] Can't allocate memory for the message buffer");
00247 }
00248
00249 actual_len = (long) recvfrom(sock_handle,*msg_buff,msglen,0,NULL,0);
00250 if (SOCKET_OP_FAILED(actual_len)) return SOCK_READMSG_FAILED;
00251
00252
00253
00254 if ((unsigned int)actual_len != msglen)
00255 xsb_warn("[SOCKET_RECV] Message length %ld differs from the header value %ld",
00256 msglen, actual_len);
00257
00258 return SOCK_OK;
00259 }
00260
00261 static int socket_accept(CTXTdeclc SOCKET *sock_handle, int timeout) {
00262 SOCKET sock_handle_in = (SOCKET) ptoc_int(CTXTc 2);
00263 if (read_select(sock_handle_in, timeout)) {
00264 *sock_handle = accept(sock_handle_in, NULL, NULL);
00265 return NORMAL_TERMINATION;
00266 } else {
00267 return TIMED_OUT;
00268 }
00269 }
00270
00271 static int socket_connect(CTXTdeclc int *rc, int timeout) {
00272 int error;
00273 socklen_t len;
00274 SOCKET sock_handle;
00275 int domain, portnum;
00276 SOCKADDR_IN socket_addr;
00277
00278 domain = ptoc_int(CTXTc 2);
00279 sock_handle = (SOCKET) ptoc_int(CTXTc 3);
00280 portnum = ptoc_int(CTXTc 4);
00281
00283 translate_domain(domain, &domain);
00284
00285
00286 FillWithZeros(socket_addr);
00287 socket_addr.sin_port = htons((unsigned short)portnum);
00288 socket_addr.sin_family = AF_INET;
00289 socket_addr.sin_addr.s_addr =
00290 inet_addr((char*)get_host_IP(ptoc_string(CTXTc 5)));
00291
00292
00293 if (timeout > 0) {
00294
00295
00296
00297 if(! SET_SOCKET_BLOCKING(sock_handle, block_false)) {
00298 xsb_error("Can't save options");
00299 return TIMER_SETUP_ERR;
00300 }
00301
00302
00303 *rc = connect(sock_handle,(PSOCKADDR)&socket_addr,sizeof(socket_addr));
00304 error = XSB_SOCKET_ERRORCODE;
00305
00306
00307 if(! SET_SOCKET_BLOCKING(sock_handle, block_true)) {
00308 xsb_error("Can't restore the flags: %d (0x%x)", XSB_SOCKET_ERRORCODE, XSB_SOCKET_ERRORCODE);
00309 return TIMER_SETUP_ERR;
00310 }
00311
00312
00313
00314 if(*rc < 0 && error != EINPROGRESS && error != EWOULDBLOCK) {
00315 *rc = error;
00316 return NORMAL_TERMINATION;
00317 }
00318
00319
00320 error = write_select(sock_handle, timeout);
00321
00322 if(error == 0) {
00323 closesocket(sock_handle);
00324 *rc = XSB_SOCKET_ERRORCODE;
00325 return TIMED_OUT;
00326 }
00327
00328
00329 len=sizeof(error);
00330 error = GETSOCKOPT(sock_handle, SOL_SOCKET, SO_ERROR, &error, &len);
00331 if(error < 0) {
00332 xsb_error("GETSOCKOPT failed");
00333 *rc = error;
00334 return NORMAL_TERMINATION;
00335 }
00336
00337
00338 if(error) {
00339 *rc = error;
00340 return NORMAL_TERMINATION;
00341 }
00342
00343 *rc = sock_handle;
00344 return NORMAL_TERMINATION;
00345 } else {
00346 *rc = connect(sock_handle,(PSOCKADDR)&socket_addr,sizeof(socket_addr));
00347 return NORMAL_TERMINATION;
00348 }
00349 }
00350
00351 static int socket_recv(CTXTdeclc int *rc, char** buffer, unsigned long *buffer_len, int timeout) {
00352 SOCKET sock_handle = (SOCKET) ptoc_int(CTXTc 2);
00353 if (read_select(sock_handle, timeout)) {
00354 *rc = readmsg(sock_handle, buffer, buffer_len);
00355 return NORMAL_TERMINATION;
00356 } else {
00357 return TIMED_OUT;
00358 }
00359 }
00360
00361 static int socket_send(CTXTdeclc int *rc, int timeout) {
00362 SOCKET sock_handle = (SOCKET) ptoc_int(CTXTc 2);
00363 char *send_msg_aux = ptoc_string(CTXTc 3);
00364 unsigned int msg_body_len, network_encoded_len;
00365 char *message_buffer;
00366
00367 if (!write_select(sock_handle, timeout)) {
00368 return TIMED_OUT;
00369 }
00370
00371 msg_body_len = strlen(send_msg_aux);
00372
00373
00374 message_buffer = mem_calloc(msg_body_len + XSB_MSG_HEADER_LENGTH + 1, sizeof(char),LEAK_SPACE);
00375 if (message_buffer == NULL) {
00376 xsb_abort("[SOCKET_SEND] Can't allocate memory for the message buffer");
00377 }
00378
00379 network_encoded_len = (unsigned int) htonl((unsigned long int) msg_body_len);
00380 memcpy((void*) (message_buffer), (void *) &network_encoded_len, XSB_MSG_HEADER_LENGTH);
00381 strcpy(message_buffer + XSB_MSG_HEADER_LENGTH, send_msg_aux);
00382
00383 *rc = sendto(sock_handle, message_buffer, msg_body_len+XSB_MSG_HEADER_LENGTH, 0, NULL, 0);
00384 mem_dealloc(message_buffer,(msg_body_len + XSB_MSG_HEADER_LENGTH + 1)*sizeof(char),LEAK_SPACE);
00385
00386 return NORMAL_TERMINATION;
00387 }
00388
00389 static int socket_get0(CTXTdeclc int *rc, char* message_read, int timeout) {
00390 SOCKET sock_handle;
00391 sock_handle = (SOCKET) ptoc_int(CTXTc 2);
00392 if (read_select(sock_handle, timeout)) {
00393 *rc = recvfrom(sock_handle, message_read, 1, 0, NULL, 0);
00394 return NORMAL_TERMINATION;
00395 } else {
00396 return TIMED_OUT;
00397 }
00398 }
00399
00400 static int socket_put(CTXTdeclc int *rc, int timeout) {
00401 SOCKET sock_handle;
00402 char tmpch;
00403
00404 sock_handle = (SOCKET) ptoc_int(CTXTc 2);
00405 tmpch = (char)ptoc_int(CTXTc 3);
00406
00407 if (write_select(sock_handle, timeout)) {
00408 *rc = sendto(sock_handle, &tmpch, 1, 0, NULL,0);
00409 return NORMAL_TERMINATION;
00410 } else {
00411 return TIMED_OUT;
00412 }
00413 }
00414
00415
00416
00417 xsbBool xsb_socket_request(CTXTdecl)
00418 {
00419 int ecode = 0;
00420 int timeout_flag;
00421 SOCKET sock_handle;
00422 int domain, portnum;
00423 SOCKADDR_IN socket_addr;
00424 struct linger sock_linger_opt;
00425 int rc;
00426 char *message_buffer;
00427 unsigned long msg_len;
00428 char char_read;
00429
00430 switch (ptoc_int(CTXTc 1)) {
00431 case SOCKET_ROOT:
00432
00433
00434 domain = ptoc_int(CTXTc 2);
00435 if (!translate_domain(domain, &domain)) {
00436 return FALSE;
00437 }
00438
00439 sock_handle = socket(domain, SOCK_STREAM, IPPROTO_TCP);
00440
00441
00442 if (BAD_SOCKET(sock_handle)) {
00443 ecode = XSB_SOCKET_ERRORCODE;
00444 perror("SOCKET_REQUEST");
00445 } else {
00446 ecode = SOCK_OK;
00447 }
00448
00449 ctop_int(CTXTc 3, (SOCKET) sock_handle);
00450
00451 return set_error_code(CTXTc ecode, 4, "SOCKET_REQUEST");
00452
00453 case SOCKET_BIND:
00454
00455
00456 sock_handle = (SOCKET) ptoc_int(CTXTc 3);
00457 portnum = ptoc_int(CTXTc 4);
00458 domain = ptoc_int(CTXTc 2);
00459
00460 if (!translate_domain(domain, &domain)) {
00461 return FALSE;
00462 }
00463
00464
00465
00466 FillWithZeros(socket_addr);
00467 socket_addr.sin_port = htons((unsigned short)portnum);
00468 socket_addr.sin_family = AF_INET;
00469 #ifndef WIN_NT
00470 socket_addr.sin_addr.s_addr = htonl(INADDR_ANY);
00471 #endif
00472
00473 rc = bind(sock_handle, (PSOCKADDR) &socket_addr, sizeof(socket_addr));
00474
00475
00476 if (SOCKET_OP_FAILED(rc)) {
00477 ecode = XSB_SOCKET_ERRORCODE;
00478 perror("SOCKET_BIND");
00479 } else
00480 ecode = SOCK_OK;
00481
00482 return set_error_code(CTXTc ecode, 5, "SOCKET_BIND");
00483
00484 case SOCKET_LISTEN:
00485
00486 sock_handle = (SOCKET) ptoc_int(CTXTc 2);
00487 rc = listen(sock_handle, ptoc_int(CTXTc 3));
00488
00489
00490 if (SOCKET_OP_FAILED(rc)) {
00491 ecode = XSB_SOCKET_ERRORCODE;
00492 perror("SOCKET_LISTEN");
00493 } else
00494 ecode = SOCK_OK;
00495
00496 return set_error_code(CTXTc ecode, 4, "SOCKET_LISTEN");
00497
00498 case SOCKET_ACCEPT:
00499 timeout_flag = socket_accept(CTXTc &rc, (int)pflags[SYS_TIMER]);
00500
00501 if (timeout_flag == TIMED_OUT) {
00502 return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND");
00503 } else {
00504
00505 if (BAD_SOCKET(rc)) {
00506 ecode = XSB_SOCKET_ERRORCODE;
00507 perror("SOCKET_ACCEPT");
00508 sock_handle = rc;
00509 } else {
00510 sock_handle = rc;
00511 ecode = SOCK_OK;
00512 }
00513
00514 ctop_int(CTXTc 3, (SOCKET) sock_handle);
00515
00516 return set_error_code(CTXTc ecode, 4, "SOCKET_ACCEPT");
00517 }
00518 case SOCKET_CONNECT: {
00519
00520
00521 timeout_flag = socket_connect(CTXTc &rc, (int)pflags[SYS_TIMER]);
00522
00523 if (timeout_flag == TIMED_OUT) {
00524 return set_error_code(CTXTc TIMEOUT_ERR, 6, "SOCKET_CONNECT");
00525 } else if (timeout_flag == TIMER_SETUP_ERR) {
00526 return set_error_code(CTXTc TIMER_SETUP_ERR, 6, "SOCKET_CONNECT");
00527 } else {
00528
00529 if (SOCKET_OP_FAILED(rc)) {
00530 ecode = XSB_SOCKET_ERRORCODE;
00531 perror("SOCKET_CONNECT");
00532
00533 closesocket(ptoc_int(CTXTc 3));
00534 } else {
00535 ecode = SOCK_OK;
00536 }
00537 return set_error_code(CTXTc ecode, 6, "SOCKET_CONNECT");
00538 }
00539 }
00540
00541 case SOCKET_CLOSE:
00542
00543
00544 sock_handle = (SOCKET)ptoc_int(CTXTc 2);
00545
00546
00547 rc = closesocket(sock_handle);
00548 if (SOCKET_OP_FAILED(rc)) {
00549 ecode = XSB_SOCKET_ERRORCODE;
00550 perror("SOCKET_CLOSE");
00551 } else
00552 ecode = SOCK_OK;
00553
00554 return set_error_code(CTXTc ecode, 3, "SOCKET_CLOSE");
00555
00556 case SOCKET_RECV:
00557
00558 timeout_flag = socket_recv(CTXTc &rc, &message_buffer, &msg_len, (int)pflags[SYS_TIMER]);
00559
00560 if (timeout_flag == TIMED_OUT) {
00561 return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND");
00562 } else {
00563
00564 switch (rc) {
00565 case SOCK_OK:
00566 ecode = SOCK_OK;
00567 break;
00568 case SOCK_READMSG_FAILED:
00569 ecode = XSB_SOCKET_ERRORCODE;
00570 perror("SOCKET_RECV");
00571 break;
00572 case SOCK_READMSG_EOF:
00573 ecode = SOCK_EOF;
00574 break;
00575 default:
00576 xsb_abort("[SOCKET_RECV] XSB bug: invalid return code from readmsg");
00577 }
00578
00579 if (message_buffer != NULL) {
00580 ctop_string(CTXTc 3, (char*)string_find(message_buffer, 1));
00581 mem_dealloc(message_buffer,msg_len,OTHER_SPACE);
00582 } else {
00583 ctop_string(CTXTc 3, (char*)string_find("", 1));
00584 }
00585
00586 return set_error_code(CTXTc ecode, 4, "SOCKET_RECV");
00587 }
00588
00589 case SOCKET_SEND:
00590
00591 timeout_flag = socket_send(CTXTc &rc, (int)pflags[SYS_TIMER]);
00592
00593 if (timeout_flag == TIMED_OUT) {
00594 return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND");
00595 } else {
00596
00597 if (SOCKET_OP_FAILED(rc)) {
00598 ecode = XSB_SOCKET_ERRORCODE;
00599 perror("SOCKET_SEND");
00600 } else {
00601 ecode = SOCK_OK;
00602 }
00603 return set_error_code(CTXTc ecode, 4, "SOCKET_SEND");
00604 }
00605
00606 case SOCKET_GET0:
00607
00608 message_buffer = &char_read;
00609 timeout_flag = socket_get0(CTXTc &rc, message_buffer, (int)pflags[SYS_TIMER]);
00610
00611 if (timeout_flag == TIMED_OUT) {
00612 return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND");
00613 } else {
00614
00615 switch (rc) {
00616 case 1:
00617 ctop_int(CTXTc 3,(unsigned char)message_buffer[0]);
00618 ecode = SOCK_OK;
00619 break;
00620 case 0:
00621 ecode = SOCK_EOF;
00622 break;
00623 default:
00624 ctop_int(CTXTc 3,-1);
00625 perror("SOCKET_GET0");
00626 ecode = XSB_SOCKET_ERRORCODE;
00627 }
00628
00629 return set_error_code(CTXTc ecode, 4, "SOCKET_GET0");
00630 }
00631 case SOCKET_PUT:
00632
00633 timeout_flag = socket_put(CTXTc &rc, (int)pflags[SYS_TIMER]);
00634
00635 if (timeout_flag == TIMED_OUT) {
00636 return set_error_code(CTXTc TIMEOUT_ERR, 4, "SOCKET_SEND");
00637 } else {
00638
00639 if (rc == 1) {
00640 ecode = SOCK_OK;
00641 } else if (SOCKET_OP_FAILED(rc)) {
00642 ecode = XSB_SOCKET_ERRORCODE;
00643 perror("SOCKET_PUT");
00644 }
00645
00646 return set_error_code(CTXTc ecode, 4, "SOCKET_PUT");
00647 }
00648 case SOCKET_SET_OPTION: {
00649
00650
00651 char *option_name = ptoc_string(CTXTc 3);
00652
00653 sock_handle = (SOCKET)ptoc_int(CTXTc 2);
00654
00655
00656 if (0==strcmp(option_name,"linger")) {
00657 int linger_time=ptoc_int(CTXTc 4);
00658
00659 if (linger_time < 0) {
00660 sock_linger_opt.l_onoff = FALSE;
00661 sock_linger_opt.l_linger = 0;
00662 } else {
00663 sock_linger_opt.l_onoff = TRUE;
00664 sock_linger_opt.l_linger = linger_time;
00665 }
00666
00667 if (SETSOCKOPT(sock_handle, SOL_SOCKET, SO_LINGER,
00668 &sock_linger_opt, sizeof(sock_linger_opt))
00669 < 0) {
00670 xsb_warn("[SOCKET_SET_OPTION] Cannot set socket linger time");
00671 return FALSE;
00672 }
00673 }else {
00674 xsb_warn("[SOCKET_SET_OPTION] Invalid option, `%s'", option_name);
00675 return FALSE;
00676 }
00677
00678 return TRUE;
00679 }
00680
00681 case SOCKET_SET_SELECT: {
00682
00683
00684 prolog_term R_sockfd, W_sockfd, E_sockfd;
00685 int i, connection_count;
00686 int rmax_fd=0, wmax_fd=0, emax_fd=0;
00687 char *connection_name = ptoc_string(CTXTc 2);
00688
00689
00690 R_sockfd = reg_term(CTXTc 3);
00691 W_sockfd = reg_term(CTXTc 4);
00692 E_sockfd = reg_term(CTXTc 5);
00693
00694
00695 init_connections(CTXT);
00696
00697
00698 for (i=0;i<MAXCONNECT;i++) {
00699 if ((connections[i].empty_flag==FALSE) &&
00700 (strcmp(connection_name,connections[i].connection_name)==0))
00701 xsb_abort("[SOCKET_SET_SELECT] Connection `%s' already exists!",
00702 connection_name);
00703 }
00704
00705
00706 if ((connection_count=checkslot())<MAXCONNECT) {
00707 if (connections[connection_count].connection_name == NULL) {
00708 connections[connection_count].connection_name = connection_name;
00709 connections[connection_count].empty_flag = FALSE;
00710
00711
00712 list_sockfd(R_sockfd, &connections[connection_count].readset,
00713 &rmax_fd, &connections[connection_count].read_fds,
00714 &connections[connection_count].sizer);
00715 list_sockfd(W_sockfd, &connections[connection_count].writeset,
00716 &wmax_fd, &connections[connection_count].write_fds,
00717 &connections[connection_count].sizew);
00718 list_sockfd(E_sockfd, &connections[connection_count].exceptionset,
00719 &emax_fd,&connections[connection_count].exception_fds,
00720 &connections[connection_count].sizee);
00721
00722 connections[connection_count].maximum_fd =
00723 xsb_max(xsb_max(rmax_fd,wmax_fd), emax_fd);
00724 } else
00725
00726 xsb_abort("[SOCKET_SET_SELECT] All connections are busy!");
00727 } else
00728 xsb_abort("[SOCKET_SET_SELECT] Max number of collections exceeded!");
00729
00730 return TRUE;
00731 }
00732
00733 case SOCKET_SELECT: {
00734
00735
00736
00737
00738
00739 prolog_term Avail_rsockfds, Avail_wsockfds, Avail_esockfds;
00740 prolog_term Avail_rsockfds_tail, Avail_wsockfds_tail, Avail_esockfds_tail;
00741
00742 int maxfd;
00743 int i;
00744 char *connection_name = ptoc_string(CTXTc 2);
00745 struct timeval *tv;
00746 prolog_term timeout_term;
00747 int timeout =0;
00748 int connectname_found = FALSE;
00749 int count=0;
00750
00751
00752 timeout_term = reg_term(CTXTc 3);
00753 if (isinteger(timeout_term)|isboxedinteger(timeout_term)) {
00754 timeout = oint_val(timeout_term);
00755
00756 tv = (struct timeval *)mem_alloc(sizeof(struct timeval),LEAK_SPACE);
00757 tv->tv_sec = timeout;
00758 tv->tv_usec = 0;
00759 } else
00760 tv = NULL;
00761
00762
00763 Avail_rsockfds = p2p_new(CTXT);
00764 Avail_wsockfds = p2p_new(CTXT);
00765 Avail_esockfds = p2p_new(CTXT);
00766
00767
00768 Avail_rsockfds = reg_term(CTXTc 4);
00769 Avail_wsockfds = reg_term(CTXTc 5);
00770 Avail_esockfds = reg_term(CTXTc 6);
00771
00772 Avail_rsockfds_tail = Avail_rsockfds;
00773 Avail_wsockfds_tail = Avail_wsockfds;
00774 Avail_esockfds_tail = Avail_esockfds;
00775
00776 c2p_list(CTXTc Avail_rsockfds_tail);
00777 c2p_list(CTXTc Avail_wsockfds_tail);
00778 c2p_list(CTXTc Avail_esockfds_tail);
00779
00780 for (i=0; i < MAXCONNECT; i++) {
00781
00782 if(connections[i].empty_flag==FALSE) {
00783 if (strcmp(connection_name, connections[i].connection_name) == 0) {
00784 connectname_found = TRUE;
00785 count = i;
00786 break;
00787 }
00788 }
00789 }
00790 if( i >= MAXCONNECT )
00791 xsb_abort("[SOCKET_SELECT] connection `%s' doesn't exist",
00792 connection_name);
00793
00794
00795 maxfd = connections[count].maximum_fd + 1;
00796
00797
00798 set_sockfd( count );
00799
00800
00801 rc = select(maxfd, &connections[count].readset,
00802 &connections[count].writeset,
00803 &connections[count].exceptionset, tv);
00804
00805
00806 if (rc == 0)
00807 ecode = TIMEOUT_ERR;
00808 else if (SOCKET_OP_FAILED(rc)) {
00809 perror("SOCKET_SELECT");
00810 ecode = XSB_SOCKET_ERRORCODE;
00811 } else {
00812 ecode = SOCK_OK;
00813
00814
00815 test_ready(CTXTc &Avail_rsockfds_tail, &connections[count].readset,
00816 connections[count].read_fds,connections[count].sizer);
00817
00818 test_ready(CTXTc &Avail_wsockfds_tail, &connections[count].writeset,
00819 connections[count].write_fds,connections[count].sizew);
00820
00821 test_ready(CTXTc &Avail_esockfds_tail,&connections[count].exceptionset,
00822 connections[count].exception_fds,connections[count].sizee);
00823 }
00824
00825 if (tv) mem_dealloc((struct timeval *)tv,sizeof(struct timeval),LEAK_SPACE);
00826 return set_error_code(CTXTc ecode, 7, "SOCKET_SELECT");
00827 }
00828
00829 case SOCKET_SELECT_DESTROY: {
00830
00831 char *connection_name = ptoc_string(CTXTc 2);
00832 select_destroy(connection_name);
00833 return TRUE;
00834 }
00835
00836 default:
00837 xsb_warn("[SOCKET_REQUEST] Invalid socket request %d", (int) ptoc_int(CTXTc 1));
00838 return FALSE;
00839 }
00840
00841
00842
00843 xsb_bug("SOCKET_REQUEST case %d has no return clause", ptoc_int(CTXTc 1));
00844 }
00845
00846
00847 static xsbBool set_error_code(CTXTdeclc int ErrCode, int ErrCodeArgNumber, char *Where)
00848 {
00849 prolog_term ecode_value_term, ecode_arg_term = p2p_new(CTXT);
00850
00851 ecode_value_term = reg_term(CTXTc ErrCodeArgNumber);
00852 if (!isref(ecode_value_term) &&
00853 !(isinteger(ecode_value_term)|isboxedinteger(ecode_value_term)))
00854 xsb_abort("[%s] Arg %d (the error code) must be a variable or an integer!",
00855 Where, ErrCodeArgNumber);
00856
00857 c2p_int(CTXTc ErrCode, ecode_arg_term);
00858 return p2p_unify(CTXTc ecode_arg_term, ecode_value_term);
00859 }
00860
00861
00862 static void init_connections(CTXTdecl)
00863 {
00864 int i;
00865 static int initialized = FALSE;
00866
00867 SYS_MUTEX_LOCK(MUTEX_SOCKETS);
00868
00869 if (!initialized) {
00870 for (i=0; i<MAXCONNECT; i++) {
00871 connections[i].connection_name = NULL;
00872 connections[i].maximum_fd=0;
00873 connections[i].empty_flag=TRUE;
00874
00875 FD_ZERO(&connections[i].readset);
00876 FD_ZERO(&connections[i].writeset);
00877 FD_ZERO(&connections[i].exceptionset);
00878
00879 connections[i].read_fds = 0;
00880 connections[i].write_fds = 0 ;
00881 connections[i].exception_fds = 0;
00882 connections[i].sizer= 0;
00883 connections[i].sizew = 0 ;
00884 connections[i].sizee = 0 ;
00885 }
00886 initialized = TRUE;
00887 }
00888
00889 SYS_MUTEX_UNLOCK(MUTEX_SOCKETS);
00890 }
00891
00892
00893 static void set_sockfd(int count)
00894 {
00895 int i;
00896
00897 FD_ZERO(&connections[count].readset);
00898 FD_ZERO(&connections[count].writeset);
00899 FD_ZERO(&connections[count].exceptionset);
00900
00901 for (i=0; i< connections[count].sizer; i++) {
00902
00903 FD_SET(connections[count].read_fds[i], &connections[count].readset);
00904 }
00905
00906 for (i=0; i< connections[count].sizew; i++) {
00907
00908 FD_SET(connections[count].write_fds[i], &connections[count].writeset);
00909 }
00910
00911 for (i=0; i< connections[count].sizee; i++) {
00912
00913 FD_SET(connections[count].exception_fds[i],
00914 &connections[count].exceptionset);
00915 }
00916 }
00917
00918
00919
00920
00921 static xsbBool list_sockfd(prolog_term list, fd_set *fdset, int *max_fd,
00922 int **fds, int * size)
00923 {
00924 int i=0;
00925 prolog_term local=list;
00926 prolog_term head;
00927
00928 *size = getsize(local);
00929 *fds = (int*)mem_alloc(sizeof(int)*(*size),OTHER_SPACE);
00930
00931 while (!isnil(list)) {
00932 head = p2p_car(list);
00933 (*fds)[i++] = p2c_int(head);
00934 list = p2p_cdr(list);
00935 }
00936
00937 for (i=0; i<(*size); i++) {
00938
00939 FD_SET((*fds)[i], fdset);
00940 *max_fd = xsb_max(*max_fd, (*fds)[i]);
00941 }
00942
00943 return TRUE;
00944 }
00945
00946
00947 static void test_ready(CTXTdeclc prolog_term *avail_sockfds, fd_set *fdset,
00948 int *fds, int size)
00949 {
00950 prolog_term head;
00951 int i=0;
00952
00953 for (i=0;i<size;i++) {
00954 if (FD_ISSET(fds[i], fdset)) {
00955 head = p2p_car(*avail_sockfds);
00956 c2p_int(CTXTc fds[i], head);
00957 *avail_sockfds = p2p_cdr(*avail_sockfds);
00958 c2p_list(CTXTc *avail_sockfds);
00959 }
00960 }
00961 c2p_nil(CTXTc *avail_sockfds);
00962 return;
00963 }
00964
00965
00966 static void select_destroy(char *connection_name)
00967 {
00968 int i;
00969 int connectname_found = FALSE;
00970
00971 for (i=0; i < MAXCONNECT; i++) {
00972 if(connections[i].empty_flag==FALSE) {
00973
00974 if (strcmp(connection_name, connections[i].connection_name) == 0) {
00975 connectname_found = TRUE;
00976
00977
00978 FD_ZERO(&connections[i].readset);
00979 FD_ZERO(&connections[i].writeset);
00980 FD_ZERO(&connections[i].exceptionset);
00981
00982 connections[i].connection_name = NULL;
00983 connections[i].maximum_fd = 0;
00984
00985
00986 mem_dealloc(connections[i].read_fds,connections[i].sizer,OTHER_SPACE);
00987 mem_dealloc(connections[i].write_fds,connections[i].sizew,OTHER_SPACE);
00988 mem_dealloc(connections[i].exception_fds,connections[i].sizee,OTHER_SPACE);
00989
00990 connections[i].sizer = 0;
00991 connections[i].sizew = 0 ;
00992 connections[i].sizee = 0 ;
00993
00994 connections[i].empty_flag = TRUE;
00995 break;
00996 }
00997 }
00998 }
00999
01000
01001 if (!connectname_found)
01002 xsb_abort("[SOCKET_SELECT_DESTROY] connection `%s' doesn't exist",
01003 connection_name);
01004
01005 }
01006
01007
01008 static int checkslot (void) {
01009 int i;
01010 for (i=0; i<MAXCONNECT;i++) {
01011 if (connections[i].empty_flag == TRUE) break;
01012 }
01013 return i;
01014 }
01015
01016
01017 static int getsize (prolog_term list)
01018 {
01019 int size = 0;
01020 prolog_term head;
01021
01022 while (!isnil(list)) {
01023 head = p2p_car(list);
01024 if(!(isinteger(head)|isboxedinteger(head)))
01025 xsb_abort("A non-integer socket descriptor encountered in a socket operation");
01026 list = p2p_cdr(list);
01027 size++;
01028 }
01029
01030 return size;
01031 }