/* The functions contained here should only be called by functions from functions in original library source file yclientio.c */ #include #include #include #include #include #include #include #include #include #define _USE_BSD #include #include #include #include #include #include #include #include #include /* For inet_ntoa() */ #include #include "../include/Y2/Y.h" #include "../include/Y2/Ylib.h" #include "../include/Y2/Yclientnet.h" extern void YShutdownSocket(int socket, int how, time_t timeout); extern void YCloseSocketWait(int socket, time_t timeout); static u_int64_t htonl64(u_int64_t x); static void YNetPrintError( FILE *stream, YConnection *con, u_int16_t chunk_length, u_int16_t major_op_code, u_int16_t minor_op_code, const char *mesg ); void YSetEventToBeDisconnect(YEvent *event); int YSendData(int s, const char *buf, int len); int YNetSendAudioChangePreset( YConnection *con, const char *audio_mode_name ); int YNetSendAudioChangeValues( YConnection *con, int sample_size, int channels, YDataLength sample_rate, int direction, int allow_fragmenting, int num_fragments, int fragment_size ); int YNetParseAudioChange(YCNP_STD_INPUTS_PROTO); int YNetSendCycleChange(YConnection *con, long cycle_us); int YNetParseCycleChange(YCNP_STD_INPUTS_PROTO); int YNetSendDisconnect(YConnection *con, int reason); int YNetParseDisconnect(YCNP_STD_INPUTS_PROTO); int YNetSendSetHost( YConnection *con, u_int16_t minor_op_code, YIPUnion *ip ); int YNetParseSetHost(YCNP_STD_INPUTS_PROTO); int YNetSendSetMixerChannel( YConnection *con, int mixer_code, Coefficient value1, Coefficient value2, Coefficient value3, Coefficient value4 ); int YNetSendGetMixerChannel(YConnection *con, int mixer_code); int YNetParseMixerChannel(YCNP_STD_INPUTS_PROTO); int YNetSendSoundPlay( YConnection *con, YID yid, const char *path, YDataPosition pos, YVolumeStruct *volume, int sample_rate, int repeats ); int YNetParseSoundPlay(YCNP_STD_INPUTS_PROTO); int YNetSendSoundKill(YConnection *con, YID yid); int YNetParseSoundKill(YCNP_STD_INPUTS_PROTO); int YNetSendGetSoundObjectAttributes( YConnection *con, const char *path ); int YNetParseSoundObjectAttributes(YCNP_STD_INPUTS_PROTO); int YNetSendShutdown(YConnection *con, int reason); int YNetParseShutdown(YCNP_STD_INPUTS_PROTO); int YNetSendSync(YConnection *con, long cycle_ahead_us); int YNetParseSync(YCNP_STD_INPUTS_PROTO); int YNetSendGetAudioStats(YConnection *con); int YNetParseAudioStats(YCNP_STD_INPUTS_PROTO); int YNetSendGetServerStats(YConnection *con); int YNetParseServerStats(YCNP_STD_INPUTS_PROTO); int YNetSendListAudioModes(YConnection *con); int YNetParseListAudioModes(YCNP_STD_INPUTS_PROTO); int YNetSendSetSoundObjectPlayValues( YConnection *con, YEventSoundPlay *value ); int YNetSendGetSoundObjectPlayValues(YConnection *con, YID yid); int YNetParseSoundObjectPlayValues(YCNP_STD_INPUTS_PROTO); int YNetSendClientMessage( YConnection *con, Boolean notify_self, int format, int type, const char *message, int length ); int YNetParseClientMessage(YCNP_STD_INPUTS_PROTO); int YNetSendYSHMSoundOpen(YConnection *con); int YNetParseYSHMSoundOpen(YCNP_STD_INPUTS_PROTO); int YNetSendAudioCDPlayTrack(YConnection *con, int track_number); int YNetSendAudioCDStop(YConnection *con); int YNetSendAudioCDEject(YConnection *con); int YNetParseAudioCD(YCNP_STD_INPUTS_PROTO); int YNetSendListAudioCDTracks(YConnection *con); int YNetParseListAudioCDTracks(YCNP_STD_INPUTS_PROTO); static int YNetParse( YConnection *con, YEvent *event, const u_int8_t *buf, u_int32_t chunk_length, u_int16_t major_op_code, u_int16_t minor_op_code ); int YNetRecv(YConnection *con); #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h))) #define ABSOLUTE(x) (((x) < 0) ? ((x) * -1) : (x)) static u_int64_t htonl64(u_int64_t x) { return(htonl(x)); #if 0 u_int8_t *px = (u_int8_t *)&x, *py; py[7] = px[0]; py[6] = px[1]; py[5] = px[2]; py[4] = px[3]; py[3] = px[4]; py[2] = px[5]; py[1] = px[6]; py[0] = px[7]; return(*(u_int64_t *)py); #endif } /* * Prints YIFF network error to stream. */ static void YNetPrintError( FILE *stream, YConnection *con, u_int16_t chunk_length, u_int16_t major_op_code, u_int16_t minor_op_code, const char *mesg ) { if(stream == NULL) return; fprintf( stream, "Y client protocol error on connection: 0x%.8x\n", (u_int32_t)con ); fprintf( stream, " Major OP Code: %i\n", major_op_code ); fprintf( stream, " Minor OP Code: %i\n", minor_op_code ); fprintf( stream, " Segment Size: %i bytes\n", chunk_length ); if(mesg != NULL) fprintf( stream, " Remarks: %s\n", mesg ); } /* * Turns event into a disconnect event. */ void YSetEventToBeDisconnect(YEvent *event) { if(event == NULL) return; /* Explicitly change event type to YDisconnect */ event->type = YDisconnect; /* Set disconnect reason code */ event->disconnect.reason = 0; } /* * Sends binary data in buf to connection s. */ int YSendData(int s, const char *buf, int len) { struct timeval timeout; fd_set writefds; int bytes_written; if(s < 0) return(-1); timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO(&writefds); FD_SET(s, &writefds); select(s + 1, NULL, &writefds, NULL, &timeout); if(!FD_ISSET(s, &writefds)) return(-1); bytes_written = send(s, buf, len, 0); if(bytes_written < 0) return(-1); else return(bytes_written); } /* * Sends audio mode change preset. */ int YNetSendAudioChangePreset( YConnection *con, const char *audio_mode_name ) { /* * <...audiomodename...> */ const YDataLength this_seg_len = 8 + YAudioNameMax; YDataLength actual_seg_len; int name_len; char buf[this_seg_len]; if(audio_mode_name == NULL) return(-1); *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YAudioChange); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YAudioChangePreset); name_len = MIN(strlen(audio_mode_name), YAudioNameMax); strncpy( &buf[8], audio_mode_name, name_len ); /* Do not null terminate string */ /* Since this is a variable length segment we need to * recalculate the segment length after the formatting * above and update the segment header's chunk size. */ actual_seg_len = 8 + name_len; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)actual_seg_len); return(YSendData(con->fd, buf, actual_seg_len)); } /* * Sends audio mode change values. */ int YNetSendAudioChangeValues( YConnection *con, int sample_size, int channels, YDataLength sample_rate, int direction, int allow_fragmenting, int num_fragments, int fragment_size ) { /* * * * */ const YDataLength this_seg_len = 8 + 8 + 1 + 9; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YAudioChange); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YAudioChangeValues); *(u_int16_t *)(&buf[8]) = htons((u_int16_t)sample_size); *(u_int16_t *)(&buf[10]) = htons((u_int16_t)channels); *(u_int32_t *)(&buf[12]) = htonl((u_int32_t)sample_rate); *(u_int8_t *)(&buf[16]) = (u_int8_t)direction; *(u_int8_t *)(&buf[17]) = (u_int8_t)allow_fragmenting; *(u_int32_t *)(&buf[18]) = htonl((u_int32_t)num_fragments); *(u_int32_t *)(&buf[22]) = htonl((u_int32_t)fragment_size); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses audio mode change. */ int YNetParseAudioChange(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YAudioChangeValues) { /* Parse Audio mode values */ /* * * * */ const YDataLength this_seg_len = 8 + 8 + 1 + 9; YEventAudioChange *audio = &event->audio; if(chunk_length < this_seg_len) return(-1); audio->preset = False; *audio->mode_name = '\0'; audio->sample_size = ntohs(*(u_int16_t *)(&buf[8])); audio->channels = ntohs(*(u_int16_t *)(&buf[10])); audio->sample_rate = ntohl(*(u_int32_t *)(&buf[12])); audio->direction = buf[16]; audio->allow_fragmenting = buf[17]; audio->num_fragments = ntohl(*(u_int32_t *)(&buf[18])); audio->fragment_size_bytes = ntohl(*(u_int32_t *)(&buf[22])); } else if(minor_op_code == YAudioChangePreset) { /* Parse change preset Audio mode */ /* * <...audiomodename...> */ const YDataLength base_seg_len = 8; int mode_name_len; YEventAudioChange *audio = &event->audio; if(chunk_length < base_seg_len) return(-1); mode_name_len = (YDataLength)chunk_length - (YDataLength)base_seg_len; if(mode_name_len >= YAudioNameMax) mode_name_len = YAudioNameMax - 1; if(mode_name_len > 0) { strncpy( audio->mode_name, (char *)&buf[8], mode_name_len ); audio->mode_name[mode_name_len] = '\0'; } else { audio->mode_name[0] = '\0'; } /* Clear rest of event members */ audio->preset = True; audio->sample_size = 0; audio->channels = 0; audio->sample_rate = 0; audio->direction = 0; audio->allow_fragmenting = 0; audio->num_fragments = 0; audio->fragment_size_bytes = 0; } return(0); } /* * Sends cycle change. */ int YNetSendCycleChange(YConnection *con, long cycle_us) { /* * */ const YDataLength this_seg_len = 8 + 4; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YCycleChange); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)0); *(u_int32_t *)(&buf[8]) = htonl((u_int32_t)cycle_us); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses cycle change. */ int YNetParseCycleChange(YCNP_STD_INPUTS_PROTO) { /* * */ const YDataLength this_seg_len = 8 + 4; YEventCycleChange *cycle = &event->cycle; if(chunk_length < this_seg_len) return(-1); cycle->cycle_us = ntohl(*(u_int32_t *)(&buf[8])); return(0); } /* * Sends disconnect. */ int YNetSendDisconnect(YConnection *con, int reason) { /* * */ const YDataLength this_seg_len = 8 + 2; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YDisconnect); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)0); *(u_int16_t *)(&buf[8]) = htons((u_int16_t)reason); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses disconnect. */ int YNetParseDisconnect(YCNP_STD_INPUTS_PROTO) { /* * */ const YDataLength this_seg_len = 8 + 2; YEventDisconnect *disconnect = &event->disconnect; if(chunk_length < this_seg_len) return(-1); disconnect->reason = ntohs(*(u_int16_t *)(&buf[8])); return(0); } /* * Sends a set host. */ int YNetSendSetHost( YConnection *con, u_int16_t minor_op_code, YIPUnion *ip ) { /* * */ const YDataLength this_seg_len = 8 + 4; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YSetHost); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)minor_op_code); *(u_int8_t *)(&buf[8]) = (u_int8_t)ip->charaddr[0]; *(u_int8_t *)(&buf[9]) = (u_int8_t)ip->charaddr[1]; *(u_int8_t *)(&buf[10]) = (u_int8_t)ip->charaddr[2]; *(u_int8_t *)(&buf[11]) = (u_int8_t)ip->charaddr[3]; return(YSendData(con->fd, buf, this_seg_len)); } /* * Handles set host. */ int YNetParseSetHost(YCNP_STD_INPUTS_PROTO) { /* * */ const YDataLength this_seg_len = 8 + 4; YEventHost *host = &event->host; if(chunk_length < this_seg_len) return(-1); host->op = ((minor_op_code == YSetHostAdd) ? 1 : 0); host->ip.charaddr[0] = (u_int8_t)buf[8]; host->ip.charaddr[1] = (u_int8_t)buf[9]; host->ip.charaddr[2] = (u_int8_t)buf[10]; host->ip.charaddr[3] = (u_int8_t)buf[11]; return(0); } /* * Sends a mixer channel set. */ int YNetSendSetMixerChannel( YConnection *con, int mixer_code, Coefficient value1, Coefficient value2, Coefficient value3, Coefficient value4 ) { /* * * * */ const YDataLength this_seg_len = 8 + 2 + 8 + 8; char buf[this_seg_len]; u_int32_t ival[4]; ival[0] = (u_int32_t)rint(value1 * (Coefficient)((u_int32_t)-1)); ival[1] = (u_int32_t)rint(value2 * (Coefficient)((u_int32_t)-1)); ival[2] = (u_int32_t)rint(value3 * (Coefficient)((u_int32_t)-1)); ival[3] = (u_int32_t)rint(value4 * (Coefficient)((u_int32_t)-1)); *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YMixerChannel); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YMixerChannelSet); *(u_int16_t *)(&buf[8]) = htons((u_int16_t)mixer_code); *(u_int32_t *)(&buf[10]) = htonl((u_int32_t)ival[0]); *(u_int32_t *)(&buf[14]) = htonl((u_int32_t)ival[1]); *(u_int32_t *)(&buf[18]) = htonl((u_int32_t)ival[2]); *(u_int32_t *)(&buf[22]) = htonl((u_int32_t)ival[3]); return(YSendData(con->fd, buf, this_seg_len)); } /* * Sends a mixer channel get. */ int YNetSendGetMixerChannel(YConnection *con, int mixer_code) { /* * */ const YDataLength this_seg_len = 8 + 2; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YMixerChannel); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YMixerChannelGet); *(u_int16_t *)(&buf[8]) = htons((u_int16_t)mixer_code); return(YSendData(con->fd, buf, this_seg_len)); } /* * Handles mixer device set. */ int YNetParseMixerChannel(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YMixerChannelGet) { /* * */ const YDataLength this_seg_len = 8 + 2; if(chunk_length < this_seg_len) return(-1); } else if(minor_op_code == YMixerChannelSet) { /* * * * */ const YDataLength this_seg_len = 8 + 2 + 8 + 8; YEventMixer *mixer = &event->mixer; if(chunk_length < this_seg_len) return(-1); mixer->code = ntohs(*(u_int16_t *)(&buf[8])); /* Get mixer values, check availibility with defination */ if(YMixerValues > 0) mixer->value[0] = (Coefficient)ntohl(*(u_int32_t *)(&buf[10])) / (Coefficient)((u_int32_t)-1); if(YMixerValues > 1) mixer->value[1] = (Coefficient)ntohl(*(u_int32_t *)(&buf[14])) / (Coefficient)((u_int32_t)-1); if(YMixerValues > 2) mixer->value[2] = (Coefficient)ntohl(*(u_int32_t *)(&buf[18])) / (Coefficient)((u_int32_t)-1); if(YMixerValues > 3) mixer->value[3] = (Coefficient)ntohl(*(u_int32_t *)(&buf[22])) / (Coefficient)((u_int32_t)-1); } return(0); } /* * Sends a sound play. */ int YNetSendSoundPlay( YConnection *con, YID yid, const char *path, YDataPosition pos, YVolumeStruct *volume, int sample_rate, int repeats ) { /* * * * * * <...path...> */ const YDataLength this_seg_len = 8 + 8 + 4 + 4 + 8 + YPathMax; char buf[this_seg_len]; YDataLength path_len, actual_seg_len; if(repeats < 0) repeats = 0; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YSoundObjectPlay); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)0); *(u_int32_t *)(&buf[8]) = htonl((u_int32_t)yid); *(u_int32_t *)(&buf[12]) = htonl((u_int32_t)pos); *(u_int16_t *)(&buf[16]) = htons((u_int16_t)volume->left); *(u_int16_t *)(&buf[18]) = htons((u_int16_t)volume->right); *(u_int16_t *)(&buf[20]) = htons((u_int16_t)volume->back_left); *(u_int16_t *)(&buf[22]) = htons((u_int16_t)volume->back_right); *(u_int32_t *)(&buf[24]) = htonl((u_int32_t)sample_rate); *(u_int32_t *)(&buf[28]) = htonl((u_int32_t)repeats); path_len = MIN(strlen(path), YPathMax); strncpy( &buf[32], path, path_len ); /* Do not null terminate string */ /* Since this is a variable length segment we need to * recalculate the segment length after the formatting * above and update the segment header's chunk size. */ actual_seg_len = 8 + 8 + 4 + 4 + 8 + path_len; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)actual_seg_len); return(YSendData(con->fd, buf, actual_seg_len)); } /* * Handles sound play. */ int YNetParseSoundPlay(YCNP_STD_INPUTS_PROTO) { if(True) /* No minor op codes */ { /* * * * * * * */ const YDataLength this_seg_len = 8 + 8 + 8 + 8 + 4 + 4 + 4; YEventSoundPlay *play = &event->play; if(chunk_length < this_seg_len) return(-1); #define BUF_TO_COEFFICIENT(x) ( \ (Coefficient)(x) / (Coefficient)((u_int16_t)-1) \ ) play->flags = (unsigned long)ntohl(*(u_int32_t *)(&buf[8])); play->yid = (YID)ntohl(*(u_int32_t *)(&buf[12])); play->position = (YDataPosition)ntohl(*(u_int32_t *)(&buf[16])); play->length = (YDataLength)ntohl(*(u_int32_t *)(&buf[20])); play->repeats = ntohl(*(u_int32_t *)(&buf[24])); play->total_repeats = ntohl(*(u_int32_t *)(&buf[28])); play->left_volume = BUF_TO_COEFFICIENT( ntohs(*(u_int16_t *)(&buf[32])) ); play->right_volume = BUF_TO_COEFFICIENT( ntohs(*(u_int16_t *)(&buf[34])) ); play->back_left_volume = BUF_TO_COEFFICIENT( ntohs(*(u_int16_t *)(&buf[36])) ); play->back_right_volume = BUF_TO_COEFFICIENT( ntohs(*(u_int16_t *)(&buf[38])) ); play->sample_rate = ntohl(*(u_int32_t *)(&buf[40])); #undef BUF_TO_COEFFICIENT } return(0); } /* * Sends a sound kill. */ int YNetSendSoundKill(YConnection *con, YID yid) { /* * */ const YDataLength this_seg_len = 8 + 4; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YSoundObjectKill); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)0); *(u_int32_t *)(&buf[8]) = htonl((u_int32_t)yid); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses sound kill. */ int YNetParseSoundKill(YCNP_STD_INPUTS_PROTO) { /* * */ const YDataLength this_seg_len = 8 + 4; YEventSoundKill *kill = &event->kill; if(chunk_length < this_seg_len) return(-1); kill->yid = ntohl(*(u_int32_t *)(&buf[8])); return(0); } /* * Sends get sound object attributes. */ int YNetSendGetSoundObjectAttributes( YConnection *con, const char *path ) { /* * <...path...> */ const YDataLength this_seg_len = 8 + YPathMax; YDataLength actual_seg_len; YDataLength path_len; char buf[this_seg_len]; if(path == NULL) return(-1); *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YSoundObjectAttributes); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YSoundObjectAttributesGet); path_len = MIN(strlen(path), YPathMax); strncpy( &buf[8], path, path_len ); /* Do not null terminate string */ /* Since this is a variable length segment we need to * recalculate the segment length after the formatting * above and update the segment header's chunk size. */ actual_seg_len = 8 + path_len; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)actual_seg_len); return(YSendData(con->fd, buf, actual_seg_len)); } /* * Handles sound object attributes. */ int YNetParseSoundObjectAttributes(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YSoundObjectAttributesGet) { } else if(minor_op_code == YSoundObjectAttributesSet) { /* * * * * <...path...> */ const YDataLength base_seg_len = 8 + 2 + 8 + 4; YDataLength path_len; YEventSoundObjectAttributes *soa = &event->sndobjattributes; if(chunk_length < base_seg_len) return(-1); soa->format = ntohs(*(u_int16_t *)(&buf[8])); soa->sample_size = ntohs(*(u_int16_t *)(&buf[10])); soa->channels = ntohs(*(u_int16_t *)(&buf[12])); soa->sample_rate = ntohl(*(u_int32_t *)(&buf[14])); soa->length = ntohl(*(u_int32_t *)(&buf[18])); path_len = (YDataLength)chunk_length - (YDataLength)base_seg_len; if(path_len >= YPathMax) path_len = YPathMax - 1; if(path_len > 0) { strncpy( soa->path, (char *)(&buf[22]), path_len ); soa->path[path_len] = '\0'; } else { *soa->path = '\0'; } } return(0); } /* * Sends shutdown. */ int YNetSendShutdown(YConnection *con, int reason) { /* * */ const YDataLength this_seg_len = 8 + 2; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YShutdown); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)0); *(u_int16_t *)(&buf[8]) = htons((u_int16_t)reason); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses shutdown. */ int YNetParseShutdown(YCNP_STD_INPUTS_PROTO) { /* * */ const YDataLength this_seg_len = 8 + 2; YEventShutdown *shutdown = &event->shutdown; if(chunk_length < this_seg_len) return(-1); shutdown->reason = ntohs(*(u_int16_t *)(&buf[8])); return(0); } /* * Sends sync. */ int YNetSendSync(YConnection *con, long cycle_ahead_us) { /* * */ const YDataLength this_seg_len = 8 + 4; char buf[this_seg_len]; /* Sanitize cycle_ahead_us */ if(cycle_ahead_us < 0) cycle_ahead_us = 0; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YSync); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)0); *(u_int32_t *)(&buf[8]) = htonl((u_int32_t)cycle_ahead_us); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses sync. */ int YNetParseSync(YCNP_STD_INPUTS_PROTO) { /* * */ const YDataLength this_seg_len = 8 + 4; YEventSync *sync = &event->sync; if(chunk_length < this_seg_len) return(-1); sync->cycle_ahead_us = ntohl(*(u_int32_t *)(&buf[8])); return(0); } /* * Sends get audio stats. */ int YNetSendGetAudioStats(YConnection *con) { /* */ const YDataLength this_seg_len = 8; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YAudioStats); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YAudioStatsGet); return(YSendData(con->fd, buf, this_seg_len)); } /* * Handles set audio stats. */ int YNetParseAudioStats(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YAudioStatsSet) { /* * * * * * * * * * <...audio_mode_name...> */ const YDataLength base_seg_len = 8 + 1 + 8 + 8 + 8 + 4 + 9 + 1 + 1; /* const YDataLength this_seg_len = 8 + 1 + 8 + 8 + 8 + 4 + 9 + 1 + 1 + YAudioNameMax; */ YDataLength name_len; YEventAudioStats *as = &event->audiostats; if(chunk_length < base_seg_len) return(-1); as->cycle_set = (int)buf[8]; as->cycle_us = ntohl(*(u_int32_t *)(&buf[9])); as->compensated_cycle_us = ntohl(*(u_int32_t *)(&buf[13])); as->write_ahead_us = ntohl(*(u_int32_t *)(&buf[17])); as->cumulative_latency_us = ntohl(*(u_int32_t *)(&buf[21])); as->sample_size = ntohs(*(u_int16_t *)(&buf[25])); as->channels = ntohs(*(u_int16_t *)(&buf[27])); as->sample_rate = ntohl(*(u_int32_t *)(&buf[29])); as->bytes_per_sec = ntohl(*(u_int32_t *)(&buf[33])); as->allow_fragments = ((buf[37]) ? True : False); as->num_fragments = ntohl(*(u_int32_t *)(&buf[38])); as->fragment_size = ntohl(*(u_int32_t *)(&buf[42])); as->flip_stereo = ((buf[46]) ? True : False); as->direction = (int)buf[47]; name_len = (YDataLength)chunk_length - (YDataLength)base_seg_len; if(name_len >= YAudioNameMax) name_len = YAudioNameMax - 1; if(name_len > 0) { strncpy( as->mode_name, (char *)(&buf[48]), name_len ); as->mode_name[name_len] = '\0'; } else { *as->mode_name = '\0'; } } return(0); } /* * Send get server stats. */ int YNetSendGetServerStats(YConnection *con) { /* */ const YDataLength this_seg_len = 8; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YServerStats); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YServerStatsGet); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses server stats. */ int YNetParseServerStats(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YServerStatsGet) { /* Parse server stats get */ /* */ const YDataLength this_seg_len = 8; if(chunk_length < this_seg_len) return(-1); } else if(minor_op_code == YServerStatsSet) { /* Parse server stats set */ /* * * * * <...vendor_name, server_name, sound_name...> */ const YDataLength base_seg_len = 8 + 8 + 2 + 8; YEventServerStats *sstat = &event->serverstats; if(chunk_length < base_seg_len) return(-1); sstat->protocol_version_major = ntohl(*(u_int32_t *)(&buf[8])); sstat->protocol_version_minor = ntohl(*(u_int32_t *)(&buf[12])); sstat->cycle_load = (double)ntohs(*(u_int16_t *)(&buf[16])) / (double)((u_int16_t)-1); sstat->start_time = (u_int64_t)htonl64(*(u_int64_t *)(&buf[18])); /* Begin parsing strings */ if(chunk_length > base_seg_len) { const char *s = (const char *)&buf[base_seg_len], *s_end = (const char *)&buf[chunk_length]; /* Vendor name */ char c, *ts = sstat->vendor_name; int i = 0, tlen = YVendorNameMax; while((s < s_end) && (i < tlen)) { ts[i] = c = *s; if(c == '\0') break; s++; i++; } if(i < tlen) ts[i] = '\0'; else ts[tlen - 1] = '\0'; /* Server name */ ts = sstat->server_name; i = 0; tlen = YServerNameMax; s++; while((s < s_end) && (i < tlen)) { ts[i] = c = *s; if(c == '\0') break; s++; i++; } if(i < tlen) ts[i] = '\0'; else ts[tlen - 1] = '\0'; /* Sound name */ ts = sstat->sound_name; i = 0; tlen = YSoundNameMax; s++; while((s < s_end) && (i < tlen)) { ts[i] = c = *s; if(c == '\0') break; s++; i++; } if(i < tlen) ts[i] = '\0'; else ts[tlen - 1] = '\0'; } /* More items to be added in future */ } return(0); } /* * Send list audio modes. */ int YNetSendListAudioModes(YConnection *con) { /* */ const YDataLength this_seg_len = 8; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YListAudioModes); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YListAudioModesGet); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses list audio modes. */ int YNetParseListAudioModes(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YListAudioModesGet) { /* Parse list audio modes get */ /* */ const YDataLength this_seg_len = 8; if(chunk_length < this_seg_len) return(-1); } else if(minor_op_code == YListAudioModesSet) { /* Parse list audio modes set */ /* * * * * <...audiomodename...> */ const YDataLength base_seg_len = 8 + 8 + 8 + 6; int name_len; YEventAudioChange *audio = &event->audio; if(chunk_length < base_seg_len) return(-1); /* We use the YEventAudioChange audio event for convience * in the fetching and organization of these values. */ name_len = (YDataLength)chunk_length - (YDataLength)base_seg_len; if(name_len >= YAudioNameMax) name_len = YAudioNameMax - 1; if(name_len > 0) { strncpy( audio->mode_name, (char *)&buf[30], name_len ); audio->mode_name[name_len] = '\0'; } else { *audio->mode_name = '\0'; } audio->preset = True; audio->sample_rate = ntohl(*(u_int32_t *)(&buf[8])); audio->channels = ntohl(*(u_int32_t *)(&buf[12])); audio->sample_size = ntohl(*(u_int32_t *)(&buf[16])); audio->fragment_size_bytes = ntohl(*(u_int32_t *)(&buf[20])); audio->direction = (u_int8_t)buf[24]; audio->allow_fragmenting = (u_int8_t)buf[25]; audio->num_fragments = ntohl(*(u_int32_t *)(&buf[26])); } return(0); } /* * Sends set sound object play values. */ int YNetSendSetSoundObjectPlayValues( YConnection *con, YEventSoundPlay *value ) { /* * * * * * */ const YDataLength this_seg_len = 8 + 8 + 8 + 4 + 4 + 4; char buf[this_seg_len]; #define COEFFICIENT_TO_BUF16(x) (u_int16_t)( \ (Coefficient)(x) * (Coefficient)((u_int16_t)-1) \ ) *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YSoundObjectPlayValues); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YSoundObjectPlayValuesSet); *(u_int32_t *)(&buf[8]) = htonl((u_int32_t)value->flags); *(u_int32_t *)(&buf[12]) = htonl((u_int32_t)value->yid); *(u_int32_t *)(&buf[16]) = htonl((u_int32_t)value->position); *(u_int32_t *)(&buf[20]) = htonl((u_int32_t)value->total_repeats); *(u_int16_t *)(&buf[24]) = htons(COEFFICIENT_TO_BUF16( value->left_volume )); *(u_int16_t *)(&buf[26]) = htons(COEFFICIENT_TO_BUF16( value->right_volume )); *(u_int16_t *)(&buf[28]) = htons(COEFFICIENT_TO_BUF16( value->back_left_volume )); *(u_int16_t *)(&buf[30]) = htons(COEFFICIENT_TO_BUF16( value->back_right_volume )); *(u_int32_t *)(&buf[32]) = htonl((u_int32_t)value->sample_rate); #undef COEFFICIENT_TO_BUF16 return(YSendData(con->fd, buf, this_seg_len)); } /* * Sends get sound object play values. */ int YNetSendGetSoundObjectPlayValues(YConnection *con, YID yid) { /* * */ const YDataLength this_seg_len = 8 + 4; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YSoundObjectPlayValues); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YSoundObjectPlayValuesGet); *(u_int32_t *)(&buf[8]) = htonl((u_int32_t)yid); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses a sound object play values. */ int YNetParseSoundObjectPlayValues(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YSoundObjectPlayValuesGet) { } else if(minor_op_code == YSoundObjectPlayValuesSet) { /* Parse sound object play values set */ /* * * * * * * */ const YDataLength this_seg_len = 8 + 8 + 8 + 8 + 4 + 4 + 4; YEventSoundPlay *play = &event->play; if(chunk_length < this_seg_len) return(-1); #define BUF_TO_COEFFICIENT(x) ( \ (Coefficient)(x) / (Coefficient)((u_int16_t)-1) \ ) play->flags = (unsigned long)ntohl(*(u_int32_t *)(&buf[8])); play->yid = (YID)ntohl(*(u_int32_t *)(&buf[12])); play->position = (YDataPosition)ntohl(*(u_int32_t *)(&buf[16])); play->length = (YDataLength)ntohl(*(u_int32_t *)(&buf[20])); play->repeats = ntohl(*(u_int32_t *)(&buf[24])); play->total_repeats = ntohl(*(u_int32_t *)(&buf[28])); play->left_volume = BUF_TO_COEFFICIENT( ntohs(*(u_int16_t *)(&buf[32])) ); play->right_volume = BUF_TO_COEFFICIENT( ntohs(*(u_int16_t *)(&buf[34])) ); play->back_left_volume = BUF_TO_COEFFICIENT( ntohs(*(u_int16_t *)(&buf[36])) ); play->back_right_volume = BUF_TO_COEFFICIENT( ntohs(*(u_int16_t *)(&buf[38])) ); play->sample_rate = ntohl(*(u_int32_t *)(&buf[40])); #undef BUF_TO_COEFFICIENT } return(0); } /* * Sends a client message. */ int YNetSendClientMessage( YConnection *con, Boolean notify_self, int format, int type, const char *message, int length ) { /* * * * <...message...> */ const YDataLength this_seg_len = 8 + 8 + 1 + YClientMessageMessageMax; YDataLength actual_seg_len = 8 + 8 + 1; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YClientMessage); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YClientMessageSend); *(u_int32_t *)(&buf[8]) = htonl((u_int32_t)format); *(u_int32_t *)(&buf[12]) = htonl((u_int32_t)type); *(u_int8_t *)(&buf[16]) = (u_int8_t)notify_self; if((message != NULL) && (length > 0)) { int len = MIN(length, YClientMessageMessageMax); memcpy(&buf[17], message, len); actual_seg_len += len; } /* Since this is a variable length segment we need to * recalculate the segment length after the formatting * above and update the segment header's chunk size. */ *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)actual_seg_len); return(YSendData(con->fd, buf, actual_seg_len)); } /* * Parses a client message. */ int YNetParseClientMessage(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YClientMessageReceive) { /* * * <...message...> */ const YDataLength base_seg_len = 8 + 8; YEventClientMessage *clientmessage = &event->clientmessage; YDataLength len; if(chunk_length < base_seg_len) return(-1); clientmessage->format = ntohl(*(u_int32_t *)(&buf[8])); clientmessage->type = ntohl(*(u_int32_t *)(&buf[12])); clientmessage->message[0] = '\0'; clientmessage->message[YClientMessageMessageMax - 1] = '\0'; clientmessage->length = len = MIN( chunk_length - base_seg_len, YClientMessageMessageMax ); if(len > 0) memcpy( clientmessage->message, &buf[16], len ); } return(0); } /* * Sends a YSHM sound open. */ int YNetSendYSHMSoundOpen(YConnection *con) { /* */ const YDataLength this_seg_len = 8; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YSHMSound); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YSHMSoundOpen); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses a YSHM sound open. */ int YNetParseYSHMSoundOpen(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YSHMSoundOpen) { /* * */ const YDataLength this_seg_len = 8 + 4; YEventYSHMSound *yshmsound = &event->yshmsound; if(chunk_length < this_seg_len) return(-1); yshmsound->minor_op_code = minor_op_code; yshmsound->shm_id = ntohl(*(u_int32_t *)(&buf[8])); } else if(minor_op_code == YSHMSoundClose) { /* * */ const YDataLength this_seg_len = 8 + 4; YEventYSHMSound *yshmsound = &event->yshmsound; if(chunk_length < this_seg_len) return(-1); yshmsound->minor_op_code = minor_op_code; yshmsound->shm_id = ntohl(*(u_int32_t *)(&buf[8])); } return(0); } /* * Send audio CD play track. */ int YNetSendAudioCDPlayTrack(YConnection *con, int track_number) { /* * */ const YDataLength this_seg_len = 8 + 4; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YAudioCD); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YAudioCDPlayTrack); *(u_int32_t *)(&buf[8]) = htonl((u_int32_t)track_number); return(YSendData(con->fd, buf, this_seg_len)); } /* * Send audio CD stop. */ int YNetSendAudioCDStop(YConnection *con) { /* */ const YDataLength this_seg_len = 8; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YAudioCD); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YAudioCDStop); return(YSendData(con->fd, buf, this_seg_len)); } /* * Send audio CD eject. */ int YNetSendAudioCDEject(YConnection *con) { /* */ const YDataLength this_seg_len = 8; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YAudioCD); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YAudioCDEject); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parse audio CD (play track, stop, and eject). */ int YNetParseAudioCD(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YAudioCDStatsGet) { } else if(minor_op_code == YAudioCDStatsSet) { } else if(minor_op_code == YAudioCDPlayTrack) { /* Parse audio CD play track */ /* * */ const YDataLength base_seg_len = 8 + 4; YEventAudioCDStats *acds = &event->audiocdstats; if(chunk_length < base_seg_len) return(-1); acds->minor_op_code = minor_op_code; acds->track_number = ntohl(*(u_int32_t *)(&buf[8])); acds->track_start_time = 0; acds->track_length = 0; } else if(minor_op_code == YAudioCDStop) { /* Parse audio CD stop */ /* */ const YDataLength base_seg_len = 8; YEventAudioCDStats *acds = &event->audiocdstats; if(chunk_length < base_seg_len) return(-1); acds->minor_op_code = minor_op_code; acds->track_number = 0; acds->track_start_time = 0; acds->track_length = 0; } else if(minor_op_code == YAudioCDEject) { /* Parse audio CD eject */ /* */ const YDataLength base_seg_len = 8; YEventAudioCDStats *acds = &event->audiocdstats; if(chunk_length < base_seg_len) return(-1); acds->minor_op_code = minor_op_code; acds->track_number = 0; acds->track_start_time = 0; acds->track_length = 0; } return(0); } /* * Send list audio CD tracks. */ int YNetSendListAudioCDTracks(YConnection *con) { /* */ const YDataLength this_seg_len = 8; char buf[this_seg_len]; *(u_int32_t *)(&buf[0]) = htonl((u_int32_t)this_seg_len); *(u_int16_t *)(&buf[4]) = htons((u_int16_t)YAudioCDTracksList); *(u_int16_t *)(&buf[6]) = htons((u_int16_t)YAudioCDTracksListGet); return(YSendData(con->fd, buf, this_seg_len)); } /* * Parses list audio CD tracks. */ int YNetParseListAudioCDTracks(YCNP_STD_INPUTS_PROTO) { if(minor_op_code == YAudioCDTracksListGet) { } else if(minor_op_code == YAudioCDTracksListSet) { /* Parse list audio CD track set */ /* * * * * <...track_name...> */ const YDataLength base_seg_len = 8 + 4 + 8 + 8; YEventAudioCDStats *acds = &event->audiocdstats; int len; if(chunk_length < base_seg_len) return(-1); acds->minor_op_code = minor_op_code; acds->track_number = ntohl(*(u_int32_t *)(&buf[8])); acds->track_start_time = ntohl(*(u_int64_t *)(&buf[12])); acds->track_length = ntohl(*(u_int64_t *)(&buf[20])); len = MIN(chunk_length - base_seg_len, YAudioCDTrackNameMax - 1); if(len > 0) strncpy( acds->track_name, (const char *)(&buf[28]), len ); acds->track_name[len] = '\0'; } return(0); } /* * Parses the buffer buf recieved from the server, this function * should be called from YNetRecv(). */ static int YNetParse( YConnection *con, YEvent *event, const u_int8_t *buf, u_int32_t chunk_length, u_int16_t major_op_code, u_int16_t minor_op_code ) { int status; event->type = major_op_code; switch(major_op_code) { case YAudioChange: status = YNetParseAudioChange(YCNP_STD_INPUTS); break; case YCycleChange: status = YNetParseCycleChange(YCNP_STD_INPUTS); break; case YDisconnect: status = YNetParseDisconnect(YCNP_STD_INPUTS); break; case YSetHost: status = YNetParseSetHost(YCNP_STD_INPUTS); break; case YListHosts: /* Work on this later */ break; case YMixerChannel: status = YNetParseMixerChannel(YCNP_STD_INPUTS); break; case YListMixers: /* Work on this later */ break; case YSoundObjectPlay: status = YNetParseSoundPlay(YCNP_STD_INPUTS); break; case YSoundObjectKill: status = YNetParseSoundKill(YCNP_STD_INPUTS); break; case YSoundObjectAttributes: status = YNetParseSoundObjectAttributes(YCNP_STD_INPUTS); break; case YShutdown: status = YNetParseShutdown(YCNP_STD_INPUTS); break; case YSync: status = YNetParseSync(YCNP_STD_INPUTS); break; case YAudioStats: status = YNetParseAudioStats(YCNP_STD_INPUTS); break; case YServerStats: status = YNetParseServerStats(YCNP_STD_INPUTS); break; case YListAudioModes: status = YNetParseListAudioModes(YCNP_STD_INPUTS); break; case YSoundObjectPlayValues: status = YNetParseSoundObjectPlayValues(YCNP_STD_INPUTS); break; case YClientMessage: status = YNetParseClientMessage(YCNP_STD_INPUTS); break; case YSHMSound: status = YNetParseYSHMSoundOpen(YCNP_STD_INPUTS); break; case YAudioCD: status = YNetParseAudioCD(YCNP_STD_INPUTS); break; case YAudioCDTracksList: status = YNetParseListAudioCDTracks(YCNP_STD_INPUTS); break; default: /* Unknown op code, so set event type to 0 */ event->type = 0; break; } return(0); } /* * This function is called by YGetNextEvent(). * * Returns the number of segments handled or -1 on fatal error. * Fatal error implies the connection is no longer usable. * * This function may close the connection and set the con->fd * to -1 if a YDisconnect or YShutdown event is recieved. */ int YNetRecv(YConnection *con) { /* Maximum events to fetch per recieve, further events are * discarded. */ const int max_event_fetch_loops = 10000; int i, n, loops, status; struct timeval timeout; fd_set readfds; u_int8_t *buf_ptr; int bytes_read, segments_handled; u_int32_t chunk_length; u_int16_t major_op_code, minor_op_code; YEvent *event_ptr; if(con->buf == NULL) return(-1); if(con->buf_cont < 0) con->buf_cont = 0; /* Make sure that con->buf_len is greater than con->buf_cont */ if((con->buf_len - con->buf_cont) <= 0) { /* Buffer overflowed and unable to parse, so reset it * and disconnect connection since there is no way to * seek the next chunk position anymore. */ con->buf_cont = 0; fprintf( stderr, "YNetRecv(): Connection 0x%.8x: Contents overflowed buffer length %ld.\n", (u_int32_t)con, con->buf_len ); /* Force disconnect */ if(con->fd > -1) { YShutdownSocket(con->fd, SHUT_RDWR, 30l); YCloseSocketWait(con->fd, 30l); con->fd = -1; } return(-1); } /* Check if there are any data to recieve */ timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO(&readfds); FD_SET(con->fd, &readfds); status = select(con->fd + 1, &readfds, NULL, NULL, &timeout); if(status == -1) perror("select"); if(!FD_ISSET(con->fd, &readfds)) return(0); buf_ptr = con->buf + con->buf_cont; bytes_read = recv( con->fd, buf_ptr, con->buf_len - con->buf_cont, MSG_NOSIGNAL ); if(bytes_read == 0) { /* Shutdown and close the socket */ if(con->fd > -1) { YShutdownSocket(con->fd, SHUT_RDWR, 30l); close(con->fd); con->fd = -1; } return(-1); } else if(bytes_read < 0) { /* Handle error */ const int error_code = errno; switch(error_code) { /* These errors are okay, return 0 indicating no data * read but also no error */ case EWOULDBLOCK: #if (EAGAIN != EWOULDBLOCK) case EAGAIN: #endif case EINTR: return(0); break; /* All other errors, force disconnect and return -1 */ default: /* Force disconnect */ if(con->fd > -1) { YShutdownSocket(con->fd, SHUT_RDWR, 30l); YCloseSocketWait(con->fd, 30l); con->fd = -1; } return(-1); break; } } /* Increment byte count indicating contents in buffer */ con->buf_cont += bytes_read; /* Sanitize buf_cont to the number of bytes allocated in the * buffer. This will be checked on the next loop if they * are equal and indicate an overflow if that happens. */ if(con->buf_cont > con->buf_len) con->buf_cont = con->buf_len; /* Begin handling each segment, handle no more than * max_event_fetch_loops from the recieved buffer. */ segments_handled = 0; for(loops = 0; loops < max_event_fetch_loops; loops++) { /* Check if we did not get the first 8 bytes (needed for the * chunk size, major op code, and minor op code). */ if(con->buf_cont < 8) break; /* All chunks start off with the same format, that being: * <4 bytes, chunk length> <2 bytes, major op code> * <2 bytes, minor op code> */ chunk_length = (u_int32_t)MAX( (long)ntohl(*((u_int32_t *)(&con->buf[0]))), (long)0 ); major_op_code = ntohs(*((u_int16_t *)(&con->buf[4]))); minor_op_code = ntohs(*((u_int16_t *)(&con->buf[6]))); /* Recieved data indicated chunk length less than 8 bytes? */ if(chunk_length < 8) { /* This should never happen, so consider this a fatal * error. Report it and force disconnect. */ YNetPrintError( stderr, con, chunk_length, major_op_code, minor_op_code, "Recieved a segment with header specified chunk length less than 8 bytes" ); if(con->fd > -1) { YShutdownSocket(con->fd, SHUT_RDWR, 30l); YCloseSocketWait(con->fd, 30l); con->fd = -1; } return(-1); } /* Did we not get the entire chunk? In other words does the * buffer contents value suggest that we do not have the * entire chunk? */ if((YDataLength)chunk_length > (YDataLength)con->buf_cont) break; /* Increment total number of queued events */ if(con->total_queued_events < 0) con->total_queued_events = 0; con->total_queued_events++; if(con->total_queued_events > YQueuedEventsMax) { /* Queued events overflowed */ con->total_queued_events = YQueuedEventsMax; /* Need to force close connection for this */ if(con->fd > -1) { YShutdownSocket(con->fd, SHUT_RDWR, 30l); YCloseSocketWait(con->fd, 30l); con->fd = -1; } fprintf(stderr, "YNetRecv(): Connection 0x%.8x: Limit of %i queued events exceeded.\n", (u_int32_t)con, YQueuedEventsMax ); return(-1); } /* Allocate a new queued event */ con->queued_event = (YEvent *)realloc( con->queued_event, con->total_queued_events * sizeof(YEvent) ); if(con->queued_event == NULL) { /* Memory allocation error */ con->total_queued_events = 0; /* Need to force close connection for this */ if(con->fd > -1) { YShutdownSocket(con->fd, SHUT_RDWR, 30l); YCloseSocketWait(con->fd, 30l); con->fd = -1; } return(-1); } /* Get pointer to newly allocated queued event segment */ event_ptr = &(con->queued_event[ con->total_queued_events - 1 ]); /* Parse recieved buffer segement and put data into event * structure event_ptr. */ YNetParse( con, event_ptr, con->buf, chunk_length, major_op_code, minor_op_code ); segments_handled++; /* Shift the buffer */ for(i = 0, n = chunk_length; n < con->buf_cont; i++, n++ ) con->buf[i] = con->buf[n]; /* Decrease buffer contents */ con->buf_cont = (YDataLength)con->buf_cont - (YDataLength)chunk_length; if(con->buf_cont < 0) con->buf_cont = 0; /* Post event handling; check special case if the event we * just parsed is either YDisconnect or YShutdown */ if((event_ptr->type == YDisconnect) || (event_ptr->type == YShutdown) ) { /* Need to force close connection when we recieve either * of these events. */ if(con->fd > -1) { YShutdownSocket(con->fd, SHUT_RDWR, 30l); YCloseSocketWait(con->fd, 30l); con->fd = -1; } } } /* Return number of segments handled which implies number of * events that were handled */ return(segments_handled); }