#include "system.h" #ifdef __MAC__ #include "GUSI.h" #endif #include "tcpip.hpp" #include "dprint.hpp" #include #ifdef __MAC__ extern tcpip_protocol tcpip; #else tcpip_protocol tcpip; #endif //#define TCPIP_DEBUG //{{{ net logging stuff /* FILE *log_file=NULL; extern int net_start(); void net_log(char *st, void *buf, long size) { if (!log_file) { if (net_start()) log_file=fopen("client.log","wb"); else log_file=fopen("server.log","wb"); } dprintf(log_file,"%s%d - ",st,size); int i; for (i=0;iaddr,0,sizeof(a->addr)); memcpy(&a->addr.sin_addr,*l_hn->h_addr_list,4); return a; #else char my_name[100]; // check to see if this address is 'hostname' gethostname(my_name,100); ip_address *ret = 0; if (my_name[0]<'0' || my_name[0]>'9') { struct hostent *l_hn=gethostbyname(my_name); if (l_hn) { ip_address *a=new ip_address(); memset(&a->addr,0,sizeof(a->addr)); memcpy(&a->addr.sin_addr,*l_hn->h_addr_list,4); return a; } else { dprintf("Enter ip address:"); gets(my_name); } } char tmp[4],*np; sockaddr_in host; np = my_name; for (int i=0; i<4; i++) { int num = 0; while (*np) { if (*np=='.') { np++; break; } num = num*10 + *np - '0'; np++; } tmp[i] = num; } memset( (char*) &host,0, sizeof(host)); host.sin_family = AF_INET; host.sin_addr.s_addr = htonl(INADDR_ANY); memcpy(&host.sin_addr,tmp,sizeof(in_addr)); return new ip_address(&host); #endif } //}}}/////////////////////////////////// net_address *tcpip_protocol::get_node_address(char *&server_name, int def_port, int force_port) //{{{ { sockaddr_in host; if (server_name[0]>='0' && server_name[0]<='9') { char tmp[4],*np; np = server_name; for (int i=0; i<4; i++) { int num = 0; while (*np && *np!=':') { if (*np=='.') { np++; break; } num = num*10 + *np - '0'; np++; } tmp[i] = num; if (*np == ':' & !force_port) { int x; if (sscanf(np+1,"%d",&x)==1) def_port=x; } } memset( (char*) &host,0, sizeof(host)); host.sin_family = AF_INET; host.sin_port = htons(def_port); host.sin_addr.s_addr = htonl(INADDR_ANY); memcpy(&host.sin_addr,tmp,sizeof(in_addr)); return new ip_address(&host); } else { char name[256],*np; np=name; while (*server_name && *server_name!=':' && *server_name!='/') *(np++)=*(server_name)++; *np=0; if (*server_name==':') { server_name++; char port[256],*p; p=port; while (*server_name && *server_name!='/') *(p++)=*(server_name++); *p=0; int x; if (!force_port) { if (sscanf(port,"%d",&x)==1) def_port=x; else return 0; } } if (*server_name=='/') server_name++; hostent *hp=gethostbyname(name); if (!hp) { dprintf("unable to locate server named '%s'\n",name); return 0; } memset( (char*) &host,0, sizeof(host)); host.sin_family = AF_INET; host.sin_port = htons(def_port); host.sin_addr.s_addr = htonl(INADDR_ANY); memcpy(&host.sin_addr,hp->h_addr,hp->h_length); } return new ip_address(&host); } //}}}/////////////////////////////////// net_socket *tcpip_protocol::connect_to_server(net_address *addr, net_socket::socket_type sock_type) //{{{ { if (addr->protocol_type()!=net_address::IP) { dprintf("Procotol type not supported in the executable\n"); return NULL; } int socket_fd=socket(AF_INET,sock_type==net_socket::SOCKET_SECURE ? SOCK_STREAM : SOCK_DGRAM,0); if (socket_fd<0) { dprintf("unable to create socket (too many open files?)\n"); return 0; } #ifndef __MAC__ int zz; if (setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&zz,sizeof(zz))<0) { dprintf("could not set socket option reuseaddr"); return 0; } #endif if (connect(socket_fd, (struct sockaddr *) &((ip_address *)addr)->addr, sizeof( ((ip_address *)addr)->addr ))==-1) { dprintf("unable to connect\n"); close(socket_fd); return 0; } if (sock_type==net_socket::SOCKET_SECURE) return new tcp_socket(socket_fd); else return new udp_socket(socket_fd); } //}}}/////////////////////////////////// net_socket *tcpip_protocol::create_listen_socket(int &port, net_socket::socket_type sock_type) //{{{ { int socket_fd=socket(AF_INET,sock_type==net_socket::SOCKET_SECURE ? SOCK_STREAM : SOCK_DGRAM,0); if (socket_fd<0) { dprintf("unable to create socket (too many open files?)\n"); return 0; } #ifndef __MAC__ int zz; if (setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&zz,sizeof(zz))<0) { dprintf("could not set socket option reuseaddr"); return 0; } #endif net_socket *s; if (sock_type==net_socket::SOCKET_SECURE) s=new tcp_socket(socket_fd); else s=new udp_socket(socket_fd); if (s->listen(port)==0) { delete s; return 0; } return s; } //}}}/////////////////////////////////// net_socket *tcpip_protocol::start_notify(int port, void *data, int len) //{{{ { if (responder) { delete responder; delete bcast; responder = 0; } int resp_len = strlen(notify_response); notify_len = len + resp_len + 1; strcpy(notify_data,notify_response); notify_data[resp_len] = '.'; memcpy(notify_data+resp_len+1,data,len); // create notifier socket #ifdef TCPIP_DEBUG dprintf("Creating notifier on port %d\n",port); #endif notifier = create_listen_socket(port, net_socket::SOCKET_FAST); if (notifier) { notifier->read_selectable(); notifier->write_unselectable(); } else dprintf("Couldn't start notifier\n"); return notifier; } //}}}/////////////////////////////////// void tcpip_protocol::end_notify() //{{{ { if (notifier) delete notifier; notifier = 0; notify_len = 0; } //}}}/////////////////////////////////// int tcpip_protocol::handle_notification() //{{{ { if (!notifier) return 0; if (notifier->ready_to_read()) { char buf[513]; int len; // got a notification request "broadcast" ip_address *addr; #ifdef TCPIP_DEBUG dprintf("Notifier: "); #endif len = notifier->read(buf, 512, (net_address**)&addr); #ifdef TCPIP_DEBUG if (len>0) { buf[len] = 0; dprintf("[%s] ",buf); } #endif if (addr && len>0) { buf[len] = 0; if (strcmp(buf, notify_signature)==0) { char s[256]; #ifdef TCPIP_DEBUG addr->store_string(s,256); dprintf("responding to %s",s); #endif // send notification data to requester notifier->write(notify_data,notify_len,addr); } delete addr; } #ifdef TCPIP_DEBUG dprintf("\n"); #endif return 1; } if (notifier->error()) { dprintf("Error on notification socket!\n"); return 1; } return 0; } //}}}/////////////////////////////////// net_address *tcpip_protocol::find_address(int port, char *name) //{{{ { // name should be a 256 byte buffer char s[256]; end_notify(); if (!responder) { //#ifdef TCPIP_DEBUG dprintf("Creating responder on port %d\n",port); //#endif responder = create_listen_socket(port, net_socket::SOCKET_FAST); responder->read_selectable(); responder->write_unselectable(); bcast = (ip_address *)get_local_address(); bcast->set_port(port); //#ifdef TCPIP_DEBUG *((unsigned char *)(&bcast->addr.sin_addr)+3) = 255; bcast->store_string(s,256); dprintf("Simulating broadcast to [%s]\n",s); //#endif *((unsigned char *)(&bcast->addr.sin_addr)+3) = 0; } if (responder) { int i; for (i=0; i<5; i++) { #ifdef TCPIP_DEBUG bcast->store_string(s,256); dprintf("\r[%s]",s); #endif int found = 0; for (p_request p = servers.begin(); !found && p!=servers.end(); ++p) if ( *((*p)->addr) == *bcast ) found = 1; for (p_request q = returned.begin(); !found && q!=returned.end(); ++q) if ( *((*q)->addr) == *bcast ) found = 1; if (!found) { responder->write((void*)notify_signature, strlen(notify_signature),bcast); select(0); } *((unsigned char *)(&bcast->addr.sin_addr)+3) += 1; select(0); if (!servers.empty()) break; } } if (servers.empty()) return 0; servers.move_next(servers.begin_prev(), returned.begin_prev()); ip_address *ret = (ip_address*)(*returned.begin())->addr->copy(); strcpy(name,(*returned.begin())->name); #ifdef TCPIP_DEBUG ret->store_string(s,256); dprintf("Found [%s]\n",s); #endif return ret; } //}}}/////////////////////////////////// void tcpip_protocol::reset_find_list() //{{{ { p_request p; for (p=servers.begin(); p!=servers.end(); ++p) delete (*p)->addr; for (p=returned.begin(); p!=returned.end(); ++p) delete (*p)->addr; servers.erase_all(); returned.erase_all(); } //}}}/////////////////////////////////// int tcpip_protocol::handle_responder() //{{{ { if (!responder) return 0; if (responder->ready_to_read()) { char buf[513]; int len; // got a notification response ip_address *addr; #ifdef TCPIP_DEBUG dprintf("Responder: "); #endif len = responder->read(buf, 512, (net_address**)&addr); #ifdef TCPIP_DEBUG if (len>0) { buf[len] = 0; dprintf("[%s] ",buf); } #endif if (addr && len>0) { buf[len] = 0; buf[4] = 0; // ack! hard coded numbers for now if (strcmp(buf,notify_response)==0) { int found=0; for (p_request p = servers.begin(); !found && p!=servers.end(); ++p) if ( *((*p)->addr) == *addr) found = 1; for (p_request q = returned.begin(); !found && q!=returned.end(); ++q) if ( *((*q)->addr) == *addr ) found = 1; if (!found) { char s[256]; RequestItem *r = new RequestItem; r->addr = addr; strcpy(r->name,buf+5); // ack hard coded numbers for now servers.insert(r); #ifdef TCPIP_DEBUG addr->store_string(s,256); dprintf("accepted %s",s); #endif } } else { delete addr; } } #ifdef TCPIP_DEBUG dprintf("\n"); #endif return 1; } if (responder->error()) { dprintf("Error on responder socket!\n"); return 1; } return 0; } //}}}/////////////////////////////////// tcpip_protocol::tcpip_protocol() //{{{ : notifier(0), notify_len(0), responder(0) { #ifdef __MAC__ GUSISetup(GUSIwithSIOUXSockets); GUSISetup(GUSIwithPPCSockets); #endif FD_ZERO(&master_set); FD_ZERO(&master_write_set); FD_ZERO(&read_set); FD_ZERO(&exception_set); FD_ZERO(&write_set); } //}}}/////////////////////////////////// int tcpip_protocol::select(int block) //{{{ { int ret; memcpy(&read_set,&master_set,sizeof(master_set)); memcpy(&exception_set,&master_set,sizeof(master_set)); memcpy(&write_set,&master_write_set,sizeof(master_set)); if (block) { ret = 0; while (ret == 0) { // get number of sockets ready from system call ret = ::select(FD_SETSIZE,&read_set,&write_set,&exception_set,NULL); // remove notifier & responder events from the count of sockets selected if (handle_notification()) ret--; if (handle_responder()) ret--; } } else { timeval tv={0,0}; // get number of sockets ready from system call ret = ::select(FD_SETSIZE,&read_set,&write_set,&exception_set,&tv); // remove notifier & responder events from the count of sockets selected if (handle_notification()) ret--; if (handle_responder()) ret--; } return ret; } //}}}/////////////////////////////////// void tcpip_protocol::cleanup() //{{{ { if (notifier) end_notify(); reset_find_list(); if (responder) { delete responder; delete bcast; responder = 0; } } //}}}/////////////////////////////////// //{{{ Revision Log /*////////////////////////////////////////////////////////////////////// $Log$ //////////////////////////////////////////////////////////////////////*/ //}}} //{{{ Emacs Locals // Local Variables: // folded-file: t // End: //}}}