/* returns index of new client on the list */ int handle_incoming_conn(Arraylist list, char *servername, int listenfd){ /* Incoming Connection */ struct sockaddr_storage remoteaddr; socklen_t addrlen = sizeof(remoteaddr); int newfd = accept(listenfd, (struct sockaddr *)&remoteaddr, &addrlen); if (newfd == -1) { DEBUG_PERROR("accept"); return -1; } DPRINTF(DEBUG_SOCKETS,"handle_incoming_conn: new connection on socket %d\n",newfd); return addClientToList(list, servername, newfd, &remoteaddr); }
int send_packet(int peer_id, int type, int seq, int ack, char* body, int body_len) { DPRINTF(DEBUG_SOCKETS, "send packet to peer:%d type:%d seq:%d ack:%d body_len:%d\n", peer_id, type, seq, ack, body_len); struct io_peer *peer = NULL; HASH_FIND(hh_id, peers_id, &peer_id, sizeof(int), peer); if (peer == NULL) { fprintf(stderr, "Unknown peer id %d\n", peer_id); return -1; } char data[sizeof(struct packet_header) + body_len]; struct packet_header *header = (struct packet_header *) data; header->magic = PACKET_MAGIC; header->version = PACKET_VERSION; header->header_len = sizeof(struct packet_header); header->total_len = (uint16_t) (header->header_len + body_len); header->type = (unsigned int) type; header->seq = (unsigned int) seq; header->ack = (unsigned int) ack; if (header->type == PACKET_ACK) { --header->ack; } packet_hton(header); if (body && body_len) { memcpy(data + sizeof(struct packet_header), body, (size_t) body_len); } int ret = spiffy_sendto(peer_sockfd, data, sizeof(data), MSG_NOSIGNAL, (const struct sockaddr *) &peer->addr, sizeof(struct sockaddr_in)); if (ret == -1) { DEBUG_PERROR("Cannot send packet\n"); } return ret; }
enum ach_status ach_create( const char *channel_name, size_t frame_cnt, size_t frame_size, ach_create_attr_t *attr) { ach_header_t *shm; int fd; size_t len; /* fixme: truncate */ /* open shm */ { len = sizeof( ach_header_t) + frame_cnt*sizeof( ach_index_t ) + frame_cnt*frame_size + 3*sizeof(uint64_t); if( attr && attr->map_anon ) { /* anonymous (heap) */ shm = (ach_header_t *) malloc( len ); fd = -1; }else { int oflag = O_EXCL | O_CREAT; /* shm */ if( ! channel_name_ok( channel_name ) ) return ACH_INVALID_NAME; if( attr ) { if( attr->truncate ) oflag &= ~O_EXCL; } if( (fd = fd_for_channel_name( channel_name, oflag )) < 0 ) { return check_errno();; } { /* make file proper size */ /* FreeBSD needs ftruncate before mmap, Linux can do either order */ int r; int i = 0; do { r = ftruncate( fd, (off_t) len ); }while(-1 == r && EINTR == errno && i++ < ACH_INTR_RETRY); if( -1 == r ) { DEBUG_PERROR( "ftruncate"); return ACH_FAILED_SYSCALL; } } /* mmap */ if( (shm = (ach_header_t *)mmap( NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0) ) == MAP_FAILED ) { DEBUG_PERROR("mmap"); DEBUGF("mmap failed %s, len: %"PRIuPTR", fd: %d\n", strerror(errno), len, fd); return ACH_FAILED_SYSCALL; } } memset( shm, 0, len ); shm->len = len; } { /* initialize synchronization */ { /* initialize condition variables */ int r; pthread_condattr_t cond_attr; if( (r = pthread_condattr_init(&cond_attr)) ) { DEBUG_PERROR("pthread_condattr_init"); return ACH_FAILED_SYSCALL; } /* Process Shared */ if( ! (attr && attr->map_anon) ) { /* Set shared if not anonymous mapping Default will be private. */ if( (r = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED)) ) { DEBUG_PERROR("pthread_condattr_setpshared"); return ACH_FAILED_SYSCALL; } } /* Clock */ if( attr && attr->set_clock ) { if( (r = pthread_condattr_setclock(&cond_attr, attr->clock)) ) { DEBUG_PERROR("pthread_condattr_setclock"); return ACH_FAILED_SYSCALL; } } else { if( (r = pthread_condattr_setclock(&cond_attr, ACH_DEFAULT_CLOCK)) ) { DEBUG_PERROR("pthread_condattr_setclock"); return ACH_FAILED_SYSCALL; } } if( (r = pthread_cond_init(&shm->sync.cond, &cond_attr)) ) { DEBUG_PERROR("pthread_cond_init"); return ACH_FAILED_SYSCALL; } if( (r = pthread_condattr_destroy(&cond_attr)) ) { DEBUG_PERROR("pthread_condattr_destroy"); return ACH_FAILED_SYSCALL; } } { /* initialize mutex */ int r; pthread_mutexattr_t mutex_attr; if( (r = pthread_mutexattr_init(&mutex_attr)) ) { DEBUG_PERROR("pthread_mutexattr_init"); return ACH_FAILED_SYSCALL; } if( (r = pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED)) ) { DEBUG_PERROR("pthread_mutexattr_setpshared"); return ACH_FAILED_SYSCALL; } /* Error Checking Mutex */ #ifdef PTHREAD_MUTEX_ERRORCHECK_NP if( (r = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK_NP)) ) { DEBUG_PERROR("pthread_mutexattr_settype"); return ACH_FAILED_SYSCALL; } #endif /* Priority Inheritance Mutex */ #ifdef PTHREAD_PRIO_INHERIT if( (r = pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_INHERIT)) ) { DEBUG_PERROR("pthread_mutexattr_setprotocol"); return ACH_FAILED_SYSCALL; } #endif if( (r = pthread_mutex_init(&shm->sync.mutex, &mutex_attr)) ) { DEBUG_PERROR("pthread_mutexattr_init"); return ACH_FAILED_SYSCALL; } if( (r = pthread_mutexattr_destroy(&mutex_attr)) ) { DEBUG_PERROR("pthread_mutexattr_destroy"); return ACH_FAILED_SYSCALL; } } } /* initialize name */ strncpy( shm->name, channel_name, ACH_CHAN_NAME_MAX ); /* initialize counts */ shm->index_cnt = frame_cnt; shm->index_head = 0; shm->index_free = frame_cnt; shm->data_head = 0; shm->data_free = frame_cnt * frame_size; shm->data_size = frame_cnt * frame_size; assert( sizeof( ach_header_t ) + shm->index_free * sizeof( ach_index_t ) + shm->data_free + 3*sizeof(uint64_t) == len ); *ACH_SHM_GUARD_HEADER(shm) = ACH_SHM_GUARD_HEADER_NUM; *ACH_SHM_GUARD_INDEX(shm) = ACH_SHM_GUARD_INDEX_NUM; *ACH_SHM_GUARD_DATA(shm) = ACH_SHM_GUARD_DATA_NUM; shm->magic = ACH_SHM_MAGIC_NUM; if( attr && attr->map_anon ) { attr->shm = shm; } else { int r; /* remove mapping */ r = munmap(shm, len); if( 0 != r ){ DEBUG_PERROR("munmap"); return ACH_FAILED_SYSCALL; } /* close file */ int i = 0; do { IFDEBUG( i ? DEBUGF("Retrying close()\n"):0 ); r = close(fd); }while( -1 == r && EINTR == errno && i++ < ACH_INTR_RETRY ); if( -1 == r ){ DEBUG_PERROR("close"); return ACH_FAILED_SYSCALL; } } return ACH_OK; }
int main( int argc, char *argv[] ) { /* for parsing args */ extern char *optarg; extern int optind; int ch; /* vars */ int i,j; int listenfd; /* select vars */ fd_set read_set; int fdmax; /* client arr */ Arraylist clientList; /* channel arr */ Arraylist channelList; /* servername */ char servername[MAX_SERVERNAME+1]; while ((ch = getopt(argc, argv, "hD:")) != -1) switch (ch) { case 'D': if (set_debug(optarg)) { exit(0); } break; case 'h': default: /* FALLTHROUGH */ usage(); } argc -= optind; argv += optind; if (argc < 2) { usage(); } signal(SIGPIPE, SIG_IGN); init_node(argv[0], argv[1]); printf( "I am node %lu and I listen on port %d for new users\n", curr_nodeID, curr_node_config_entry->irc_port ); /* Start your engines here! */ if (gethostname(servername,MAX_SERVERNAME) < 0){ perror("gethostname"); return EXIT_FAILURE; } servername[MAX_SERVERNAME] = '\0'; /* delegate all function calling to setupListenSocket. It should print out relevant err messages. */ listenfd = setupListenSocket(curr_node_config_entry->irc_port); if (listenfd < 0){ return EXIT_FAILURE; } /* initialize client array */ clientList = arraylist_create(); /* initialize channel array */ channelList = arraylist_create(); /* prepare for select */ fdmax = listenfd; FD_ZERO(&master_set); FD_ZERO(&write_set); FD_SET(listenfd,&master_set); /* FD_ZERO(&write_set); initially no data to write */ /* main loop!! */ for (;;){ int retval; read_set = master_set; /* wait until any sockets become available */ retval = select(fdmax+1,&read_set,&write_set,NULL,NULL); if (retval <= 0){ if (retval < 0) DEBUG_PERROR("select"); continue; /* handle errors gracefully and wait again if timed out (it shouldn't)*/ } /* at least one socket ready*/ for (i = 0; i <= fdmax; i++){ if (FD_ISSET(i, &write_set)) { int listIndex = findClientIndexBySockFD(clientList,i); client_t *thisClient = (client_t *) CLIENT_GET(clientList,listIndex); /*client data ready to be written */ int nbytes; /* iterate through item to be sent, until it will block */ Arraylist outbuf = thisClient->outbuf; while (!arraylist_is_empty(outbuf)) { /* write */ char *dataToSend = (char *) (arraylist_get(outbuf,0)) + thisClient->outbuf_offset; size_t sizeToSend = strlen(dataToSend); nbytes = send(thisClient->sock, dataToSend, sizeToSend, 0); if (nbytes <0){ /* error */ if (errno == EPIPE || errno == ECONNRESET){ /* connection lost or closed by the peer */ DPRINTF(DEBUG_SOCKETS,"send: client %d hungup\n",i); remove_client(clientList,listIndex); continue; } } else if (nbytes == sizeToSend){ /* current line completely sent */ char *toRemove = (char *) (arraylist_get(outbuf,0)); arraylist_removeIndex(outbuf,0); free(toRemove); } else{ /* partial send */ thisClient->outbuf_offset += nbytes; break; } } if (arraylist_is_empty(outbuf)) FD_CLR(i, &write_set); } if (FD_ISSET(i, &read_set)) { if (i == listenfd){ /* incoming connection */ int newindex = handle_incoming_conn(clientList,servername,listenfd); if (newindex < 0){ continue; } client_t *newClient = CLIENT_GET(clientList,newindex); int newfd = newClient->sock; FD_SET(newfd,&master_set); if (newfd > fdmax){ fdmax = newfd; } } else{ /* client data ready */ char *tempPtr; int listIndex = findClientIndexBySockFD(clientList,i); /* for split function */ char** tokenArr; int numToken; int lastTokenTerminated; if (listIndex < 0){ close(i); FD_CLR(i,&master_set); continue; } int nbytes = recv(i, CLIENT_GET(clientList,listIndex)->inbuf + CLIENT_GET(clientList,listIndex)->inbuf_size, MAX_MSG_LEN - CLIENT_GET(clientList,listIndex)->inbuf_size, 0); /* recv failed. Either client left or error */ if (nbytes <= 0){ if (nbytes == 0){ DPRINTF(DEBUG_SOCKETS,"recv: client %d hungup\n",i); remove_client(clientList, listIndex); } else if (errno == ECONNRESET || errno == EPIPE){ DPRINTF(DEBUG_SOCKETS,"recv: client %d connection reset \n",i); remove_client(clientList, listIndex); } else{ perror("recv"); } continue; } /* NULL terminate to use strpbrk */ CLIENT_GET(clientList,listIndex)->inbuf_size += nbytes; CLIENT_GET(clientList,listIndex)->inbuf[CLIENT_GET(clientList,listIndex)->inbuf_size] = '\0'; tempPtr = strpbrk(CLIENT_GET(clientList,listIndex)->inbuf,"\r\n"); if (!tempPtr){ if (CLIENT_GET(clientList,listIndex)->inbuf_size == MAX_MSG_LEN){ /* Message too long. Dump the content */ DPRINTF(DEBUG_INPUT,"recv: message longer than MAX_MESSAGE detected. The message will be discarded\n"); CLIENT_GET(clientList,listIndex)->inbuf_size = 0; } continue; } tokenArr = splitByDelimStr(CLIENT_GET(clientList,listIndex)->inbuf,"\r\n",&numToken,&lastTokenTerminated); /* since we have checked if there's delimeter beforehand, there should be at least one terminated token available*/ if (!tokenArr){ DPRINTF(DEBUG_INPUT,"splitByDelimStr: failed to split inputToken\n"); CLIENT_GET(clientList,listIndex)->inbuf_size = 0; continue; } if (!lastTokenTerminated){ CLIENT_GET(clientList,listIndex)->inbuf_size = strlen(tokenArr[numToken-1]); memcpy(CLIENT_GET(clientList,listIndex)->inbuf,tokenArr[numToken-1],CLIENT_GET(clientList,listIndex)->inbuf_size); numToken--; } for (j=0;j<numToken;j++){ handle_line(clientList,listIndex,channelList,servername,tokenArr[j]); } for (j = 0; j < arraylist_size(clientList); j++){ client_t *client = CLIENT_GET(clientList,j); if (arraylist_size(client->outbuf)){ FD_SET(client->sock,&write_set); } } freeTokens(&tokenArr,numToken); } } } } return 0; }