/* * socket_efun.c -- socket efuns for MudOS. * 5-92 : Dwayne Fontenot (Jacques@TMI) : original coding. * 10-92 : Dave Richards (Cynosure) : less original coding. * 4-93 : Fredrik Hubinette (hubbe@lysator.liu.se) : adapted for functionpointers */ #include "global.h" #include <sys/types.h> #include <sys/time.h> #include <sys/ioctl.h> #include <sys/socket.h> #ifdef HAVE_SYS_SOCKETVAR_H #include <sys/socketvar.h> #endif #ifdef _AIX #include <sys/select.h> #endif /* _AIX */ #include <fcntl.h> #include <netdb.h> #include <errno.h> #include <ctype.h> #include <signal.h> #include "comm.h" #include "interpret.h" #include "object.h" #include "exec.h" #include "debug.h" #include "socket_efuns.h" #include "socket_err.h" #include "main.h" #include "stralloc.h" #include "dynamic_buffer.h" #include "simulate.h" extern int errno, d_flag; extern int save_svalue_depth; extern char *error_strings[]; struct lpc_socket lpc_socks[MAX_EFUN_SOCKS]; static int socket_name_to_sin PROT((char *, struct sockaddr_in *)); /* * Initialize the LPC efun socket array */ void init_sockets() { int i; debug(8192,("init_sockets: initializing %d socket descriptor(s)\n", MAX_EFUN_SOCKS)); for (i = 0; i < MAX_EFUN_SOCKS; i++) { lpc_socks[i].fd = -1; lpc_socks[i].flags = 0; lpc_socks[i].mode = S_STREAM; lpc_socks[i].state = CLOSED; MEMSET((char *)&lpc_socks[i].l_addr, 0, sizeof (lpc_socks[i].l_addr)); MEMSET((char *)&lpc_socks[i].r_addr, 0, sizeof (lpc_socks[i].r_addr)); lpc_socks[i].owner_ob = NULL; lpc_socks[i].release_ob = NULL; SET_TO_ZERO(lpc_socks[i].read_callback); SET_TO_ZERO(lpc_socks[i].write_callback); SET_TO_ZERO(lpc_socks[i].close_callback); lpc_socks[i].r_buf = NULL; lpc_socks[i].r_off = 0; lpc_socks[i].r_len = 0; lpc_socks[i].w_buf = NULL; lpc_socks[i].w_off = 0; lpc_socks[i].w_len = 0; } } void check_svalue(struct svalue *s) { if(s->type & (T_OBJECT | T_FUNCTION)) if(s->u.ob->flags & O_DESTRUCTED) free_svalue(s); } /* * Create an LPC efun socket */ int socket_create(int mode, struct svalue *read_callback, struct svalue *close_callback) { int type, i, fd, optval; switch (mode & S_MODE_MASK) { case S_STREAM: type = SOCK_STREAM; break; case S_DATAGRAM: type = SOCK_DGRAM; break; default: return EEMODENOTSUPP; } for (i = 0; i < MAX_EFUN_SOCKS; i++) { if (lpc_socks[i].state != CLOSED) continue; fd = socket(AF_INET, type, 0); if (fd == -1) { perror("socket_create: socket"); return EESOCKET; } optval = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof (optval)) == -1) { perror("socket_create: setsockopt"); close(fd); return EESETSOCKOPT; } if (set_socket_nonblocking(fd, 1) == -1) { perror("socket_create: set_socket_nonblocking"); close(fd); return EENONBLOCK; } lpc_socks[i].fd = fd; lpc_socks[i].flags = S_HEADER; lpc_socks[i].mode = mode; lpc_socks[i].state = UNBOUND; MEMSET((char *)&lpc_socks[i].l_addr, 0, sizeof (lpc_socks[i].l_addr)); MEMSET((char *)&lpc_socks[i].r_addr, 0, sizeof (lpc_socks[i].r_addr)); lpc_socks[i].owner_ob = current_object; lpc_socks[i].release_ob = NULL; if(read_callback==NULL) { free_svalue(&lpc_socks[i].read_callback); }else{ assign_svalue(&lpc_socks[i].read_callback,read_callback); } free_svalue(&lpc_socks[i].write_callback); if (type != SOCK_DGRAM && close_callback != NULL) { assign_svalue(&lpc_socks[i].close_callback,close_callback); }else{ free_svalue(&lpc_socks[i].close_callback); } lpc_socks[i].r_buf = NULL; lpc_socks[i].r_off = 0; lpc_socks[i].r_len = 0; lpc_socks[i].w_buf = NULL; lpc_socks[i].w_off = 0; lpc_socks[i].w_len = 0; current_object->flags |= O_EFUN_SOCKET; debug(8192,("socket_create: created socket %d mode %d fd %d\n", i, mode, fd)); return i; } return EENOSOCKS; } int socket_from_stdin() { int i; for (i = 0; i < MAX_EFUN_SOCKS; i++) if (lpc_socks[i].state == CLOSED) break; if(i==MAX_EFUN_SOCKS) return EENOSOCKS; if (set_socket_nonblocking(0, 1) == -1) { perror("socket_create: set_socket_nonblocking"); return EENONBLOCK; } lpc_socks[i].state = LISTEN; current_object->flags |= O_EFUN_SOCKET; lpc_socks[i].fd = 0; lpc_socks[i].flags = S_HEADER; lpc_socks[i].mode = S_STREAM; MEMSET((char *)&lpc_socks[i].l_addr, 0, sizeof (lpc_socks[i].l_addr)); MEMSET((char *)&lpc_socks[i].r_addr, 0, sizeof (lpc_socks[i].r_addr)); lpc_socks[i].owner_ob = current_object; lpc_socks[i].release_ob = NULL; free_svalue(&lpc_socks[i].read_callback); free_svalue(&lpc_socks[i].write_callback); free_svalue(&lpc_socks[i].close_callback); lpc_socks[i].r_buf = NULL; lpc_socks[i].r_off = 0; lpc_socks[i].r_len = 0; lpc_socks[i].w_buf = NULL; lpc_socks[i].w_off = 0; lpc_socks[i].w_len = 0; current_object->flags |= O_EFUN_SOCKET; return i; } /* * Bind an address to an LPC efun socket */ int socket_bind(int fd,int port) { int len; struct sockaddr_in sin; if (fd < 0 || fd >= MAX_EFUN_SOCKS) return EEFDRANGE; if (lpc_socks[fd].state == CLOSED) return EEBADF; if (lpc_socks[fd].owner_ob != current_object) return EESECURITY; if (lpc_socks[fd].state != UNBOUND) return EEISBOUND; sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons((u_short)port); if (bind(lpc_socks[fd].fd, (struct sockaddr *)&sin, sizeof (sin)) == -1) { switch (errno) { case EADDRINUSE: return EEADDRINUSE; default: perror("socket_bind: bind"); return EEBIND; } } len = sizeof (sin); if (getsockname(lpc_socks[fd].fd, (struct sockaddr *)&lpc_socks[fd].l_addr, &len) == -1) { perror("socket_bind: getsockname"); return EEGETSOCKNAME; } lpc_socks[fd].state = BOUND; debug(8192,("socket_bind: bound socket %d to %s.%d\n", fd, inet_ntoa(lpc_socks[fd].l_addr.sin_addr), ntohs(lpc_socks[fd].l_addr.sin_port))); return EESUCCESS; } /* * Listen for connections on an LPC efun socket */ int socket_listen(int fd,struct svalue *callback) { if (fd < 0 || fd >= MAX_EFUN_SOCKS) return EEFDRANGE; if (lpc_socks[fd].state == CLOSED) return EEBADF; if (lpc_socks[fd].owner_ob != current_object) return EESECURITY; if ((lpc_socks[fd].mode & S_MODE_MASK) == S_DATAGRAM) return EEMODENOTSUPP; if (lpc_socks[fd].state == UNBOUND) return EENOADDR; if (lpc_socks[fd].state != BOUND) return EEISCONN; if (listen(lpc_socks[fd].fd, 5) == -1) { perror("socket_listen: listen"); return EELISTEN; } lpc_socks[fd].state = LISTEN; assign_svalue(&lpc_socks[fd].read_callback,callback); current_object->flags |= O_EFUN_SOCKET; debug(8192,("socket_listen: listen on socket %d\n", fd)); return EESUCCESS; } /* * Accept a connection on an LPC efun socket */ int socket_accept(int fd, struct svalue *read_callback, struct svalue * write_callback) { int len, accept_fd, i; struct sockaddr_in sin; if (fd < 0 || fd >= MAX_EFUN_SOCKS) return EEFDRANGE; if (lpc_socks[fd].state == CLOSED) return EEBADF; if (lpc_socks[fd].owner_ob != current_object) return EESECURITY; if ((lpc_socks[fd].mode & S_MODE_MASK) == S_DATAGRAM) return EEMODENOTSUPP; if (lpc_socks[fd].state != LISTEN) return EENOTLISTN; lpc_socks[fd].flags &= ~S_WACCEPT; len = sizeof (sin); accept_fd = accept(lpc_socks[fd].fd, (struct sockaddr *)&sin, (int *)&len); if (accept_fd == -1) { perror("socket_accept: accept"); switch (errno) { case EWOULDBLOCK: return EEWOULDBLOCK; case EINTR: return EEINTR; default: perror("socket_accept: accept"); return EEACCEPT; } } for (i = 0; i < MAX_EFUN_SOCKS; i++) { if (lpc_socks[i].state != CLOSED) continue; lpc_socks[i].fd = accept_fd; lpc_socks[i].flags = S_HEADER; lpc_socks[i].mode = lpc_socks[fd].mode; lpc_socks[i].state = DATA_XFER; lpc_socks[i].l_addr = lpc_socks[fd].l_addr; lpc_socks[i].r_addr = sin; lpc_socks[i].owner_ob = NULL; lpc_socks[i].release_ob = NULL; free_svalue(&lpc_socks[i].read_callback); free_svalue(&lpc_socks[i].write_callback); free_svalue(&lpc_socks[i].close_callback); lpc_socks[i].r_buf = NULL; lpc_socks[i].r_off = 0; lpc_socks[i].r_len = 0; lpc_socks[i].w_buf = NULL; lpc_socks[i].w_off = 0; lpc_socks[i].w_len = 0; lpc_socks[i].owner_ob = current_object; assign_svalue(&lpc_socks[i].read_callback,read_callback); assign_svalue(&lpc_socks[i].write_callback,write_callback); assign_svalue(&lpc_socks[i].close_callback,&lpc_socks[fd].close_callback); current_object->flags |= O_EFUN_SOCKET; debug(8192,("socket_accept: accept on socket %d\n", fd)); debug(8192,("socket_accept: new socket %d on fd %d\n", i, accept_fd)); return i; } close(accept_fd); return EENOSOCKS; } /* * Connect an LPC efun socket */ int socket_connect(int fd, char *name, struct svalue *read_callback, struct svalue *write_callback) { if (fd < 0 || fd >= MAX_EFUN_SOCKS) return EEFDRANGE; if (lpc_socks[fd].state == CLOSED) return EEBADF; if (lpc_socks[fd].owner_ob != current_object) return EESECURITY; if ((lpc_socks[fd].mode & S_MODE_MASK) == S_DATAGRAM) return EEMODENOTSUPP; switch (lpc_socks[fd].state) { case CLOSED: case UNBOUND: case BOUND: break; case LISTEN: return EEISLISTEN; case DATA_XFER: return EEISCONN; } if (!socket_name_to_sin(name, &lpc_socks[fd].r_addr)) return EEBADADDR; assign_svalue(&lpc_socks[fd].read_callback, read_callback); assign_svalue(&lpc_socks[fd].write_callback, write_callback); current_object->flags |= O_EFUN_SOCKET; if (connect(lpc_socks[fd].fd, (struct sockaddr *)&lpc_socks[fd].r_addr, sizeof (struct sockaddr_in)) == -1) { switch (errno) { case EINTR: return EEINTR; case EADDRINUSE: return EEADDRINUSE; case EALREADY: return EEALREADY; case ECONNREFUSED: return EECONNREFUSED; case EINPROGRESS: break; default: perror("socket_connect: connect"); return EECONNECT; } } lpc_socks[fd].state = DATA_XFER; lpc_socks[fd].flags |= S_BLOCKED; return EESUCCESS; } /* * Write a message on an LPC efun socket */ int socket_write(int fd,struct svalue *message,char *name) { int len, off; char *buf; struct sockaddr_in sin; if (fd < 0 || fd >= MAX_EFUN_SOCKS) return EEFDRANGE; if (lpc_socks[fd].state == CLOSED) return EEBADF; if (lpc_socks[fd].owner_ob != current_object) return EESECURITY; switch (lpc_socks[fd].mode & S_MODE_MASK) { case S_STREAM: if (lpc_socks[fd].state != DATA_XFER) return EENOTCONN; if (name != NULL) return EEBADADDR; if(lpc_socks[fd].flags & S_BLOCKED) { if(lpc_socks[fd].mode & S_BUFFERED_OUTPUT) { len = my_strlen(message) + lpc_socks[fd].w_len; buf=(char *)malloc(len+1); if (buf == NULL) fatal("Out of memory"); if(lpc_socks[fd].w_buf) MEMCPY(buf,lpc_socks[fd].w_buf+lpc_socks[fd].w_off,lpc_socks[fd].w_len); MEMCPY(buf+lpc_socks[fd].w_len,strptr(message),my_strlen(message)); buf[len]=0; if(lpc_socks[fd].w_buf) free(lpc_socks[fd].w_buf); lpc_socks[fd].w_buf = buf; lpc_socks[fd].w_off = 0; lpc_socks[fd].w_len = len; return 0; }else{ return EEALREADY; } } len = my_strlen(message); buf = (char *)xalloc(len + 1); if (buf == NULL) fatal("Out of memory"); MEMCPY(buf, strptr(message),my_strlen(message)); break; case S_DATAGRAM: if(name == NULL) return EENOADDR; if(!socket_name_to_sin(name, &sin)) return EEBADADDR; if (sendto(lpc_socks[fd].fd, strptr(message), my_strlen(message) + 1, 0, (struct sockaddr *)&sin, sizeof (sin)) == -1) { perror("socket_write: sendto"); return EESENDTO; } return EESUCCESS; default: return EEMODENOTSUPP; } off = send(lpc_socks[fd].fd, buf,len, 0); if (off == -1) { switch (errno) { case EWOULDBLOCK: break; default: free(buf); perror("socket_write: send"); return EESEND; } } if (off < len) { lpc_socks[fd].flags |= S_BLOCKED; lpc_socks[fd].w_buf = buf; lpc_socks[fd].w_off = off; lpc_socks[fd].w_len = len - off; return EECALLBACK; } free(buf); return EESUCCESS; } void parse_one_line(int fd) { int e; char *s; if((lpc_socks[fd].mode & S_MODE_MASK) != S_STREAM) return; if(!(lpc_socks[fd].mode & S_BUFFERED_INPUT)) return; if(lpc_socks[fd].r_buf == NULL) { lpc_socks[fd].flags&=~S_MORE_LINES; return; } if(lpc_socks[fd].r_len>0 && lpc_socks[fd].r_buf) { s=lpc_socks[fd].r_buf+lpc_socks[fd].r_off; for(e=0;e<lpc_socks[fd].r_len;e++) { if(s[e]=='\n') { e++; break; } } lpc_socks[fd].r_off+=e; lpc_socks[fd].r_len-=e; push_number(fd); push_shared_string(make_shared_binary_string(s,e)); lpc_socks[fd].flags |= S_MORE_LINES; debug(8192,("read_socket_handler: apply read callback\n")); check_svalue(&lpc_socks[fd].read_callback); apply_lambda(&lpc_socks[fd].read_callback, 2,1); } if(lpc_socks[fd].state==CLOSED || (lpc_socks[fd].flags & S_CLOSING)) return; if(lpc_socks[fd].r_len<1) { lpc_socks[fd].flags &= ~S_MORE_LINES; if(lpc_socks[fd].r_buf) free(lpc_socks[fd].r_buf); lpc_socks[fd].r_buf=NULL; } } void handle_line_sockets() { int i,s; do{ s=0; for(i=0;i<MAX_EFUN_SOCKS;i++) { if((lpc_socks[i].mode & S_MODE_MASK) != S_STREAM) continue; if(!(lpc_socks[i].mode & S_BUFFERED_INPUT)) continue; if(lpc_socks[i].flags & S_MORE_LINES) { parse_one_line(i); s=1; } } }while(s); } /* * Handle LPC efun socket read select events */ void socket_read_select_handler(int fd) { int cc=-1; /* make gcc happy */ int addrlen; char buf[BUF_SIZE], addr[ADDR_BUF_SIZE]; struct sockaddr_in sin; debug(8192,("read_socket_handler: fd %d state %d\n", fd, lpc_socks[fd].state)); switch (lpc_socks[fd].state) { case CLOSED: case UNBOUND: return; case BOUND: switch (lpc_socks[fd].mode & S_MODE_MASK) { case S_STREAM: break; case S_DATAGRAM: debug(8192,("read_socket_handler: DATA_XFER DATAGRAM\n")); addrlen = sizeof (sin); cc = recvfrom(lpc_socks[fd].fd, buf, sizeof (buf), 0, (struct sockaddr *)&sin, &addrlen); if (cc <= 0) break; debug(8192,("read_socket_handler: read %d bytes\n", cc)); sprintf(addr, "%s %d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); push_number(fd); push_shared_string(make_shared_binary_string(buf, cc)); push_new_shared_string(addr); debug(8192,("read_socket_handler: apply\n")); check_svalue(&lpc_socks[fd].read_callback); apply_lambda(&lpc_socks[fd].read_callback, 3,1); return; } break; case LISTEN: debug(8192,("read_socket_handler: apply read callback\n")); lpc_socks[fd].flags |= S_WACCEPT; push_number(fd); check_svalue(&lpc_socks[fd].read_callback); apply_lambda(&lpc_socks[fd].read_callback, 1,1); return; case DATA_XFER: switch (lpc_socks[fd].mode & S_MODE_MASK) { case S_DATAGRAM: break; case S_STREAM: if(lpc_socks[fd].mode & S_BUFFERED_INPUT) { char *s; int e; debug(8192,("read_socket_handler: DATA_XFER STREAM (buffered)\n")); cc = recv(lpc_socks[fd].fd, buf, sizeof (buf), 0); if (cc <= 0) break; debug(8192,("read_socket_handler: read %d bytes\n", cc)); if(lpc_socks[fd].r_buf != NULL) { e=lpc_socks[fd].r_len+cc; s=(char *)malloc(e+1); strncpy(s,lpc_socks[fd].r_buf+lpc_socks[fd].r_off, lpc_socks[fd].r_len); strncpy(s+lpc_socks[fd].r_len,buf,cc); free(lpc_socks[fd].r_buf); lpc_socks[fd].r_buf=s; lpc_socks[fd].r_len=e; lpc_socks[fd].r_off=0; }else{ s=(char *)malloc(cc); strncpy(s,buf,cc); lpc_socks[fd].r_buf=s; lpc_socks[fd].r_len=cc; lpc_socks[fd].r_off=0; } lpc_socks[fd].flags |=S_MORE_LINES; return; } debug(8192,("read_socket_handler: DATA_XFER STREAM\n")); cc = recv(lpc_socks[fd].fd, buf, sizeof (buf), 0); if (cc <= 0) break; debug(8192,("read_socket_handler: read %d bytes\n", cc)); push_number(fd); push_shared_string(make_shared_binary_string(buf, cc)); debug(8192,("read_socket_handler: apply read callback\n")); check_svalue(&lpc_socks[fd].read_callback); apply_lambda(&lpc_socks[fd].read_callback, 2,1); return; } break; } if(cc == -1) { switch(errno) { case EINTR: case EWOULDBLOCK: return; } } debug(8192,("read_socket_handler: apply close callback\n")); push_number(fd); check_svalue(&lpc_socks[fd].close_callback); safe_apply_lambda(&lpc_socks[fd].close_callback, 1); socket_close(fd,1); } /* * Handle LPC efun socket write select events */ void socket_write_select_handler(int fd) { int cc; debug(8192,("write_socket_handler: fd %d state %d\n", fd, lpc_socks[fd].state)); if ((lpc_socks[fd].flags & S_BLOCKED) == 0) return; if (lpc_socks[fd].w_buf != NULL) { cc = send(lpc_socks[fd].fd, lpc_socks[fd].w_buf + lpc_socks[fd].w_off, lpc_socks[fd].w_len, 0); if (cc == -1) { #if 1 switch(errno) { case EINTR: case EWOULDBLOCK: return; } debug(8192,("read_socket_handler: apply close callback\n")); push_number(fd); check_svalue(&lpc_socks[fd].close_callback); safe_apply_lambda(&lpc_socks[fd].close_callback, 1); socket_close(fd,2); #endif return; } lpc_socks[fd].w_off += cc; lpc_socks[fd].w_len -= cc; if (lpc_socks[fd].w_len != 0) return; free(lpc_socks[fd].w_buf); lpc_socks[fd].w_buf = NULL; lpc_socks[fd].w_off = 0; } lpc_socks[fd].flags &= ~S_BLOCKED; if(lpc_socks[fd].flags & S_CLOSING) { socket_close(fd,2); return; } debug(8192,("write_socket_handler: apply write_callback\n")); push_number(fd); check_svalue(&lpc_socks[fd].write_callback); apply_lambda(&lpc_socks[fd].write_callback, 1,1); } /* * Close an LPC efun socket */ int socket_close(int fd,int force) { if(d_flag>8) printf("so_close: %d\n",fd); if (fd < 0 || fd >= MAX_EFUN_SOCKS) return EEFDRANGE; if (lpc_socks[fd].state == CLOSED) return EEBADF; if (!force && lpc_socks[fd].owner_ob != current_object) return EESECURITY; if ((lpc_socks[fd].mode & S_MODE_MASK) != S_DATAGRAM) { if(!(lpc_socks[fd].flags & S_CLOSING)) shutdown(lpc_socks[fd].fd, 0); } lpc_socks[fd].flags|=S_CLOSING; if((lpc_socks[fd].flags & S_BLOCKED) && force<2) { lpc_socks[fd].flags|=S_CLOSING; return EEALREADY; } while (close(lpc_socks[fd].fd) == -1 && errno == EINTR); /* empty while */ lpc_socks[fd].state = CLOSED; if (lpc_socks[fd].r_buf != NULL) free(lpc_socks[fd].r_buf); lpc_socks[fd].r_buf=NULL; if (lpc_socks[fd].w_buf != NULL) free(lpc_socks[fd].w_buf); lpc_socks[fd].w_buf=NULL; free_svalue(&lpc_socks[fd].read_callback); free_svalue(&lpc_socks[fd].write_callback); free_svalue(&lpc_socks[fd].close_callback); debug(8192,("socket_close: closed fd %d\n", fd)); return EESUCCESS; } /* * Release an LPC efun socket to another object */ int socket_release(int fd,struct svalue *callback) { if (fd < 0 || fd >= MAX_EFUN_SOCKS) return EEFDRANGE; if (lpc_socks[fd].state == CLOSED) return EEBADF; if (lpc_socks[fd].owner_ob != current_object) return EESECURITY; if (lpc_socks[fd].flags & S_RELEASE) return EESOCKRLSD; lpc_socks[fd].flags |= S_RELEASE; lpc_socks[fd].release_ob = callback->u.ob; push_number(fd); push_object(callback->u.ob); safe_apply_lambda(callback, 2); if ((lpc_socks[fd].flags & S_RELEASE) == 0) return EESUCCESS; lpc_socks[fd].flags &= ~S_RELEASE; lpc_socks[fd].release_ob = NULL; return EESOCKNOTRLSD; } /* * Aquire an LPC efun socket from another object */ int socket_acquire(int fd, struct svalue *read_callback, struct svalue *write_callback, struct svalue *close_callback) { if (fd < 0 || fd >= MAX_EFUN_SOCKS) return EEFDRANGE; if (lpc_socks[fd].state == CLOSED) return EEBADF; if ((lpc_socks[fd].flags & S_RELEASE) == 0) return EESOCKNOTRLSD; if (lpc_socks[fd].release_ob != current_object) return EESECURITY; lpc_socks[fd].flags &= ~S_RELEASE; lpc_socks[fd].owner_ob = current_object; lpc_socks[fd].release_ob = NULL; assign_svalue(&lpc_socks[fd].read_callback,read_callback); assign_svalue(&lpc_socks[fd].write_callback,write_callback); assign_svalue(&lpc_socks[fd].close_callback,close_callback); return EESUCCESS; } /* * Return the string representation of a socket error */ char *socket_error(int error) { error = -(error + 1); if (error < 0 || error >= ERROR_STRINGS) return "socket_error: invalid error number"; return error_strings[error]; } /* * Return the current socket owner */ struct object *get_socket_owner(int fd) { if (fd < 0 || fd >= MAX_EFUN_SOCKS) return (struct object *)NULL; if (lpc_socks[fd].state == CLOSED) return (struct object *)NULL; return lpc_socks[fd].owner_ob; } /* * Initialize a T_OBJECT svalue */ void assign_socket_owner(struct svalue *sv,struct object *ob) { if (ob != NULL) { sv->type = T_OBJECT; sv->u.ob = ob; add_ref(ob, "assign_socket_owner"); }else{ SET_TO_ZERO(*sv); } } /* * Convert a string representation of an address to a sockaddr_in */ static int socket_name_to_sin(char *name,struct sockaddr_in *sin) { int port; char *cp, addr[ADDR_BUF_SIZE]; strncpy(addr, name, ADDR_BUF_SIZE); cp = STRCHR(addr, ' '); if (cp == NULL) return 0; *cp = '\0'; port = atoi(cp + 1); sin->sin_family = AF_INET; sin->sin_port = htons((u_short)port); sin->sin_addr.s_addr = inet_addr(addr); return 1; } /* * Close any sockets owned by ob */ void close_referencing_sockets(struct object *ob) { int i; struct object *save_current_object; save_current_object = current_object; current_object = ob; for (i = 0; i < MAX_EFUN_SOCKS; i++) if (lpc_socks[i].owner_ob == ob && lpc_socks[i].state != CLOSED) socket_close(i,1); current_object = save_current_object; } /* * Return the remote address for an LPC efun socket */ int get_socket_address(int fd,char *addr,int *port) { if (fd < 0 || fd >= MAX_EFUN_SOCKS) { addr[0] = '\0'; *port = 0; return EEFDRANGE; } *port = (int)ntohs(lpc_socks[fd].r_addr.sin_port); sprintf(addr, "%s", inet_ntoa(lpc_socks[fd].r_addr.sin_addr)); return EESUCCESS; } /* * Return the string representation of a sockaddr_in */ static char *inet_address(struct sockaddr_in *sin) { static char addr[50], port[7]; if (ntohl(sin->sin_addr.s_addr) == INADDR_ANY) { strcpy(addr, "*"); }else{ strncpy(addr, inet_ntoa(sin->sin_addr),sizeof(addr)-7); } strcat(addr, "."); if (ntohs(sin->sin_port) == 0) strcpy(port, "*"); else sprintf(port, "%d", ntohs(sin->sin_port)); strcat(addr, port); return addr; } /* * Dump the LPC efun socket array */ char *dump_socket_status() { int i; char b[100]; init_buf(); my_strcat("Fd State Mode Local Address Remote Address\n"); my_strcat("-- --------- -------- --------------------- ---------------------\n"); for(i = 0; i < MAX_EFUN_SOCKS; i++) { sprintf(b,"%2d ", lpc_socks[i].fd); my_strcat(b); switch(lpc_socks[i].state){ case CLOSED: my_strcat("CLOSED "); break; case UNBOUND: my_strcat("UNBOUND"); break; case BOUND: my_strcat(" BOUND "); break; case LISTEN: my_strcat("LISTEN "); break; case DATA_XFER: my_strcat("DTXFER "); break; default: my_strcat(" ?? "); break; } my_putchar(' '); switch(lpc_socks[i].mode & S_MODE_MASK){ case S_STREAM: my_strcat("STREAM"); break; case S_DATAGRAM: my_strcat("DGRAM "); break; default: my_strcat(" ?? "); break; } my_putchar(' '); if(lpc_socks[i].mode & S_BUFFERED_INPUT) { my_putchar('I'); }else{ my_putchar('.'); } if(lpc_socks[i].mode & S_BUFFERED_OUTPUT) { my_putchar('O'); }else{ my_putchar('.'); } my_putchar(' '); sprintf(b,"%-21s ", inet_address(&lpc_socks[i].l_addr)); my_strcat(b); sprintf(b,"%-21s\n", inet_address(&lpc_socks[i].r_addr)); my_strcat(b); } return free_buf(); }