/* accept a connection on the control port */ static void do_accept(void) { int d; imc_connect *c; struct sockaddr_in sa; int size = sizeof(sa); int r; d=accept(control, (struct sockaddr *) &sa, &size); if (d<0) { imc_lerror("accept"); return; } r=fcntl(d, F_GETFL, 0); if (r<0 || fcntl(d, F_SETFL, O_NONBLOCK | r)<0) { imc_lerror("do_accept: fcntl"); close(d); return; } c=imc_new_connect(); c->state = IMC_WAIT1; c->desc = d; imc_add_event(IMC_LOGIN_TIMEOUT, ev_login_timeout, c, 1); imc_logstring("connection from %s:%d on descriptor %d", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), d); }
/* shell around imc_idle_select */ void imc_idle(int s, int us) { fd_set read, write, exc; int maxfd; struct timeval timeout; int i; FD_ZERO(&read); FD_ZERO(&write); FD_ZERO(&exc); maxfd=imc_fill_fdsets(0, &read, &write, &exc); timeout.tv_sec = s; timeout.tv_usec = us; if (maxfd) while ((i=select(maxfd+1, &read, &write, &exc, &timeout)) < 0 && errno == EINTR) /* loop, ignoring signals */ ; else while ((i=select(0, NULL, NULL, NULL, &timeout)) < 0 && errno == EINTR) ; if (i<0) { imc_lerror("imc_idle: select"); imc_shutdown_network(); return; } imc_idle_select(&read, &write, &exc, time(NULL)); }
/* write to descriptor */ static void do_write(imc_connect *c) { int size, w; if (c->state==IMC_CONNECTING) { /* Wait for server password */ c->state=IMC_WAIT2; return; } size = strlen(c->outbuf); if (!size) /* nothing to write */ return; w=write(c->desc, c->outbuf, size); if (!w || (w<0 && errno != EAGAIN && errno != EWOULDBLOCK)) { if (!c->info || !(c->info->flags & IMC_QUIET)) { if (w<0) /* write error */ { imc_lerror("%s: write", imc_getconnectname(c)); } else /* socket was closed */ { imc_logerror("%s: write: EOF", imc_getconnectname(c)); } } do_close(c); return; } if (w<0) /* EAGAIN */ return; /* throw away data we wrote */ // memmove(c->outbuf, c->outbuf+w, size-w+1); strcpy(c->outbuf,c->outbuf+w); imc_stats.tx_bytes += w; }
/* save_idlist: save idlist */ static void save_idlist(void) { FILE *out; imc_mailid *p; char name[200]; imc_sncpy(name, imc_prefix, 191); strcat(name, "mail-ids"); out=fopen(name, "w"); if (!out) { imc_lerror("save_idlist: fopen"); return; } for (p=imc_idlist->next; p; p=p->next) write_mailid(p, out); fclose(out); }
/* save mailqueue */ static void save_mq(void) { FILE *out; imc_qnode *p; char name[200]; imc_sncpy(name, imc_prefix, 189); strcat(name, "mail-queue"); out=fopen(name, "w"); if (!out) { imc_lerror("save_mq: fopen"); return; } for (p=imc_mq_head->next; p; p=p->next) write_qnode(p, out); fclose(out); }
/* save_ml: save maillist */ static void save_ml(void) { FILE *out; imc_mail *p; char name[200]; imc_sncpy(name, imc_prefix, 190); strcat(name, "mail-list"); out=fopen(name, "w"); if (!out) { imc_lerror("save_ml: fopen"); return; } for (p=imc_ml_head->next; p; p=p->next) write_mail(p, out); fclose(out); }
static int lock_prefix(void) { char lockfile[1000]; sprintf(lockfile, "%slock", imc_prefix); imc_lock_file=open(lockfile, O_CREAT|O_EXCL|O_RDWR, 0644); if (imc_lock_file<0) imc_lock_file=open(lockfile, O_RDWR, 0644); if (imc_lock_file<0) { imc_lerror("lock_prefix: open %s", lockfile); return 0; } //if (lockf(imc_lock_file, F_TLOCK, 1)<0) if (imc_lock_file<0) { close(imc_lock_file); imc_lock_file=-1; return 0; } return 1; }
/* read waiting data from descriptor. * read to a temp buffer to avoid repeated allocations */ static void do_read(imc_connect *c) { int size; int r; char temp[IMC_MAXBUF]; char *newbuf; int newsize; r=read(c->desc, temp, IMC_MAXBUF-1); if (!r || (r<0 && errno != EAGAIN && errno != EWOULDBLOCK)) { if (!c->info || !(c->info->flags & IMC_QUIET)) { if (r<0) /* read error */ { imc_lerror("%s: read", imc_getconnectname(c)); } else /* socket was closed */ { imc_logerror("%s: read: EOF", imc_getconnectname(c)); } } do_close(c); return; } if (r<0) /* EAGAIN error */ return; temp[r]=0; size=strlen(c->inbuf)+r+1; if (size>=c->insize) { #ifdef SHOW_OVERFLOW /* not an error anymore, expected and handled - shogar */ if (size>IMC_MAXBUF) { imc_logerror("%s: input buffer overflow", imc_getconnectname(c)); imc_logerror("%d: was allocated", c->insize); // do_close(c); // imc_free(c->inbuf,c->insize); // c->insize=IMC_MINBUF; // c->inbuf= imc_malloc(c->insize); // size = r + 1; // return; } #endif newsize=c->insize; while(newsize<size) newsize*=2; newbuf=imc_malloc(newsize); strcpy(newbuf, c->inbuf); imc_free(c->inbuf, c->insize); c->inbuf=newbuf; c->insize=newsize; } if (size>c->insize/2) { imc_cancel_event(ev_shrink_input, c); imc_add_event(IMC_SHRINKTIME, ev_shrink_input, c, 0); } if (size<c->insize/2 && size >= IMC_MINBUF) { newsize=c->insize; newsize/=2; newbuf=imc_malloc(newsize); strcpy(newbuf, c->inbuf); imc_free(c->inbuf, c->insize); c->inbuf=newbuf; c->insize=newsize; } strcat(c->inbuf, temp); imc_stats.rx_bytes += r; }
/* connect to given mud */ int imc_connect_to(const char *mud) { imc_info *i; imc_connect *c; int desc; struct sockaddr_in sa; char buf[IMC_DATA_LENGTH]; int r; if (imc_active == IA_NONE) { imc_qerror("IMC is not active"); return 0; } i=imc_getinfo(mud); if (!i) { imc_qerror("%s: unknown mud name", mud); return 0; } if (i->connection) { imc_qerror("%s: already connected", mud); return 0; } if (i->flags & IMC_CLIENT) { imc_qerror("%s: client-only flag is set", mud); return 0; } if (i->flags & IMC_DENY) { imc_qerror("%s: deny flag is set", mud); return 0; } if (!(i->flags & IMC_QUIET)) imc_logstring("connect to %s", mud); /* warning: this blocks. It would be better to farm the query out to * another process, but that is difficult to do without lots of changes * to the core mud code. You may want to change this code if you have an * existing resolver process running. */ if ((sa.sin_addr.s_addr=inet_addr(i->host)) == -1UL) { struct hostent *hostinfo; if (NULL == (hostinfo=gethostbyname(i->host))) { imc_logerror("imc_connect: couldn't resolve hostname"); return 0; } sa.sin_addr.s_addr = *(unsigned long *) hostinfo->h_addr; } sa.sin_port = htons(i->port); sa.sin_family = AF_INET; desc=socket(AF_INET, SOCK_STREAM, 0); if (desc<0) { imc_lerror("socket"); return 0; } r=fcntl(desc, F_GETFL, 0); if (r<0 || fcntl(desc, F_SETFL, O_NONBLOCK | r)<0) { imc_lerror("imc_connect: fcntl"); close(desc); return 0; } if (connect(desc, (struct sockaddr *)&sa, sizeof(sa))<0) if (errno != EINPROGRESS) { imc_lerror("connect"); close(desc); return 0; } c=imc_new_connect(); c->desc = desc; c->state = IMC_CONNECTING; c->info = i; imc_add_event(IMC_LOGIN_TIMEOUT, ev_login_timeout, c, 1); sprintf(buf, "PW %s %s version=%d", imc_name, i->clientpw, IMC_VERSION); do_send(c, buf); return 1; }
/* start up listening port */ void imc_startup_port(void) { int i; struct sockaddr_in sa; if (imc_active!=IA_UP) { imc_logerror("imc_startup_port: called with imc_active=%d", imc_active); return; } if (imc_port==0) { imc_logerror("imc_startup_port: called with imc_port=0"); return; } imc_logstring("binding port %d for incoming connections", imc_port); control = socket(AF_INET, SOCK_STREAM, 0); if (control<0) { imc_lerror("imc_startup_port: socket"); return; } i=1; if (setsockopt(control, SOL_SOCKET, SO_REUSEADDR, (void *)&i, sizeof(i))<0) { imc_lerror("imc_startup_port: SO_REUSEADDR"); close(control); return; } if ((i=fcntl(control, F_GETFL, 0))<0) { imc_lerror("imc_startup_port: fcntl(F_GETFL)"); close(control); return; } if (fcntl(control, F_SETFL, i | O_NONBLOCK)<0) { imc_lerror("imc_startup_port: fcntl(F_SETFL)"); close(control); return; } sa.sin_family = AF_INET; sa.sin_port = htons(imc_port); sa.sin_addr.s_addr = imc_bind; /* already in network order */ if (bind(control, (struct sockaddr *)&sa, sizeof(sa))<0) { imc_lerror("imc_startup_port: bind"); close(control); return; } if (listen(control, 1)<0) { imc_lerror("imc_startup_port: listen"); close(control); return; } imc_active=IA_LISTENING; }