void Ctransaction::recv() { const int cb_b = 2 << 10; char b[cb_b]; while (1) { socklen_t cb_a = sizeof(sockaddr_in); int r = m_s.recvfrom(mutable_data_ref(b, cb_b), reinterpret_cast<sockaddr*>(&m_a), &cb_a); if (r == SOCKET_ERROR) { if (WSAGetLastError() != WSAEWOULDBLOCK) std::cerr << "recv failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; return; } if (r < uti_size) return; switch (read_int(4, b + uti_action, b + r)) { case uta_connect: if (r >= utic_size) send_connect(data_ref(b, r)); break; case uta_announce: if (r >= utia_size) send_announce(data_ref(b, r)); break; case uta_scrape: if (r >= utis_size) send_scrape(data_ref(b, r)); break; } } }
int process_client_request (int sock_s, char *line, int total_line_num, int is_ms_server) { unsigned int nleft; int nwrite; char *ptrWrite, *ptrTemp, writeBuf[MAX_BUFFER_SIZE]; char responseBuf[MAX_LINE_NUMBER][256]; int i, next_line_num; rtsp_method_t method = UNKNOWN; int CSeq; int CL_line_num = 0; nleft = 0; nwrite = 0; bzero(responseBuf, sizeof(char) * MAX_LINE_NUMBER*256); printf("\nprocess_client_request(): \n"); for (i=0; i< total_line_num; i++) { //printf("rcvd line[%d]= %s", i,line); if ( i == 0 ) { /* the first line in the request */ if (strstr(line, "SETUP") >0 ) { method = SETUP; printf("\tmethod = SETUP\n"); } else if ( strstr(line, "PLAY") > 0 ) { method = PLAY; printf("\tmethod = PLAY\n"); } else if ( strstr(line, "TEARDOWN") > 0 ) { method = TEARDOWN; printf("\tmethod = TEARDOWN\n"); } else if ( strstr(line, "DESCRIBE") > 0 ) { method = DESCRIBE; printf("\tmethod = DESCRIBE\n"); } else if ( strstr(line, "GET_PARAMETER") >0 ) { method = GET_PARAMETER; printf("\tmethod = GET_PARAMETER\n"); } else if ( strstr(line, "PAUSE") > 0 ) { method = PAUSE; printf("\tmethod = PAUSE\n"); } else if ( strstr(line, "200 OK") >0 ) { method = ANNOUNCE_REPLY; printf("\tmethod = ANNOUNCE_REPLY"); } else { method = UNKNOWN; //printf("\tmethod = UNKNOWN\n"); } } /* done with the fisrt line */ else { /*the rest lines */ if ( strstr(line, "Content-Length") > 0 ) /* skip the conten-Length, we need to add Content_Lenght according to how many bytes we send out*/ { CL_line_num =i; //will be used for Get_parameter later } else //has no Content-Length { if (( strstr(line, "Range:") > 0 ) && (sub_choice == PLAY_NO_RANGE_HEADER)) { /* for testing when no Range: hdr is not include in PLAY response */ //do not copy teh line } else { strcpy(responseBuf[i], line); } } if (strstr(line, "CSeq") > 0) { CSeq = cseq_parser(line); //printf("\n CSeq is %d\n", CSeq); } } /*done the rest lines*/ line= line +256; /* move to next line */ } /* done for loop */ next_line_num =i; /*printf("total lines: next_line_num=%d\n", next_line_num);*/ /* build response msg */ switch (method) { case SETUP: if (sub_choice == SETUP_ERROR) { strcpy(responseBuf[0], "RTSP/1.0 404 NOT FOUND\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); break; } /* NORMAL case: 200 OK */ // if (menu_choice != ONE_MS_SERVER_AND_ONE_VOD_SERVER) // { // strcpy(responseBuf[0], "RTSP/1.0 200 OK\r\n"); // strcpy(responseBuf[next_line_num++], "Session: 4050682558055376826\r\n"); // } // else// (menu_choice == ONE_MS_SERVER_AND_ONE_VOD_SERVER) // { next_line_num = 0; strcpy(responseBuf[next_line_num++], "RTSP/1.0 200 OK\r\n"); strcpy(responseBuf[next_line_num++], "CSeq: 1\r\n"); if (sub_choice == SETUP_HAS_TIMEOUT_VALUE_RETURNED) strcpy(responseBuf[next_line_num++], "Session: 5059691751022412168;timeout=60\r\n"); else strcpy(responseBuf[next_line_num++], "Session: 5059691751022412168\r\n"); if (menu_choice == ONE_MS_SERVER_AND_ONE_VOD_SERVER) { strcpy(responseBuf[next_line_num++], "ControlSession: 8888691751022412168\r\n"); strcpy(responseBuf[next_line_num++], location_hdr); } if (vod_stream_transport_type == 1 ) //VOD_over IP { sprintf(responseBuf[next_line_num++], "StreamAddress: %s:%d\r\n", vod_server_ip_addr,VOD_SERVER_PORT); } else { sprintf(responseBuf[next_line_num++], "Tuning: frequency=11570\r\n"); } strcpy(responseBuf[next_line_num++], "Channel: Tsid=3;Svcid=12\r\n"); // } strcpy(responseBuf[next_line_num],"\r\n"); break; case PLAY: if (sub_choice == PLAY_ERROR) { strcpy(responseBuf[0], "RTSP/1.0 400 Bad Request\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); break; } /* NORMAL case: 200 OK */ strcpy(responseBuf[0], "RTSP/1.0 200 OK\r\n"); break; case PAUSE: /* NORMAL case: 200 OK */ strcpy(responseBuf[0], "RTSP/1.0 200 OK\r\n"); break; case DESCRIBE: if (sub_choice == DESCRIBE_ERROR) { strcpy(responseBuf[0], "RTSP/1.0 400 Bad Request\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); break; } /* NORMAL case: 200 OK */ strcpy(responseBuf[0], "RTSP/1.0 200 OK\r\n"); if (menu_choice != ONE_MS_SERVER_AND_ONE_VOD_SERVER) { strcpy(responseBuf[next_line_num++],"Date: Tue, 02 May 2006 00:02:31 GMT\r\n"); strcpy(responseBuf[next_line_num++],"Content-Length: 236\r\n"); strcpy(responseBuf[next_line_num++],"\r\n"); strcpy(responseBuf[next_line_num++],"v=0\r\n"); strcpy(responseBuf[next_line_num++],"o=- 1146528151955250 9727864823646 IN IP4 192.168.0.102\r\n"); strcpy(responseBuf[next_line_num++],"s=RTSP Session\r\n"); strcpy(responseBuf[next_line_num++],"t=0 0\r\n"); strcpy(responseBuf[next_line_num++],"i=\r\n"); strcpy(responseBuf[next_line_num++],"b=AS:4837\r\n"); strcpy(responseBuf[next_line_num++],"a=type:vod\r\n"); strcpy(responseBuf[next_line_num++],"a=range:npt=0-91.052\r\n"); strcpy(responseBuf[next_line_num++],"c=IN IP4 0.0.0.0\r\n"); strcpy(responseBuf[next_line_num++],"a=control:rtsp://192.168.0.241/vanhelsing.mpi\r\n"); strcpy(responseBuf[next_line_num++],"m=video 0 RTP/AVP 33\r\n"); strcpy(responseBuf[next_line_num++],"a=framerate:25.00\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); } else { strcpy(responseBuf[next_line_num++],"Content-Type: application/sdp\r\n"); strcpy(responseBuf[next_line_num++],"Content-Length: 41\r\n"); strcpy(responseBuf[next_line_num++],"\r\n"); strcpy(responseBuf[next_line_num++],"i=\r\n"); strcpy(responseBuf[next_line_num++],"a=type:vod\r\n"); strcpy(responseBuf[next_line_num++],"a=range:npt=0-139.234\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); } break; case TEARDOWN: strcpy(responseBuf[0], "RTSP/1.0 200 OK\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); break; case GET_PARAMETER: if (sub_choice == GET_PARAMETER_ERROR) { strcpy(responseBuf[0], "RTSP/1.0 400 Bad Request\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); break; } /* NORMAL case: 200 OK */ strcpy(responseBuf[0], "RTSP/1.0 200 OK\r\n"); if (CL_line_num >0 ) { next_line_num = CL_line_num; if ((menu_choice == ONE_MS_SERVER_AND_ONE_VOD_SERVER)) { if ((is_ms_server == 0) /* VOD server */ || (sub_choice == GET_PARAMETER_ALWAYS_SEND_MSG_BODY)) { strcpy(responseBuf[next_line_num++],"Content-Length: 53\r\n"); strcpy(responseBuf[next_line_num++],"\r\n"); strcpy(responseBuf[next_line_num++],"stream_state: playing\r\n"); strcpy(responseBuf[next_line_num++],"position: 92.99\r\n"); strcpy(responseBuf[next_line_num++],"Scale: 1.5\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); } else /* ms server */ { strcpy(responseBuf[next_line_num],"\r\n"); } } else { strcpy(responseBuf[next_line_num++],"Content-Length: 53\r\n"); strcpy(responseBuf[next_line_num++],"\r\n"); strcpy(responseBuf[next_line_num++],"stream_state: playing\r\n"); strcpy(responseBuf[next_line_num++],"position: 92.99\r\n"); strcpy(responseBuf[next_line_num++],"Scale: 2.5\r\n"); strcpy(responseBuf[next_line_num],"\r\n"); } } break; case ANNOUNCE_REPLY: case UNKNOWN: default: break; } /*end of switch (method) */ if (method == ANNOUNCE_REPLY ) { return 0; } /* printf("total next_line_num=%d\n", next_line_num);*/ for (i=0; i<= next_line_num; i++) { printf("\tresponseBuf[%d]=%s", i, responseBuf[i]); } if (method == UNKNOWN ) { return 0; } ptrWrite = writeBuf; bzero( ptrWrite, MAX_BUFFER_SIZE); ptrTemp= ptrWrite; for (i=0; i< next_line_num ; i++) { nleft = strlen( responseBuf[i]); /*printf("i=%d, nleft=%d\n", i, nleft);*/ strncpy(ptrTemp, responseBuf[i], nleft); ptrTemp += nleft; } /*end of for */ *ptrTemp= '\r'; ptrTemp++; *ptrTemp= '\n'; nleft= ptrTemp - ptrWrite + 1; while (nleft >0) { //printf("nleft=%d\n", nleft); if ( (nwrite = write (sock_s, ptrWrite, nleft)) < 0 ) { if (errno == EINTR) nwrite = 0; /* call write again */ else { printf("ERROR in write. i=%d\n",i); return (-1); } } /* end if */ nleft -= nwrite; ptrWrite += nwrite; } /* end of while (nleft) */ printf("sent the response, CSeq=%d\n\n", CSeq); if ((sub_choice == ANNOUNCE_EVENT_CODE_OK) || ( sub_choice == ANNOUNCE_EVENT_CODE_ERROR)) { if ( CSeq == 6 ) { printf( "send a announce\n"); send_announce( sock_s); } return 0; } return 0; }
/** * Perform the Announce/Register phase for a particular group/file * Group & encryption: ->ANNOUNCE <-REGISTER ->KEYINFO <-INFO_ACK * Group & no encryption: ->ANNOUNCE <-REGISTER ->REG_CONF * Files within a group: ->FILEINFO <-INFO_ACK * If client_key == 1, REGISTER is followed by CLIENT_KEY * Returns 1 if at least one client responded, 0 if none responded */ int announce_phase(struct finfo_t *finfo) { time_t endtime; int attempt, resend, announce, regconf, keyinfo, fileinfo, open, anyerror; int len, rval, rcv_status, last_pass, gotall, gotone, allreg, regdone, i; unsigned char *packet, *decrypted; struct uftp_h *header; struct timeval timeout; struct sockaddr_in receiver; if (finfo->file_id) { log1(0, 0, "File ID: %04X Name: %s", finfo->file_id, finfo->filename); log1(0, 0, " sending as: %s", finfo->destfname); switch (finfo->ftype) { case FTYPE_REG: log(0, 0, "Bytes: %s Blocks: %d Sections: %d", printll(finfo->size), finfo->blocks, finfo->sections); break; case FTYPE_DIR: log(0, 0, "Empty directory"); break; case FTYPE_LINK: log(0, 0, "Symbolic link to %s", finfo->linkname); break; } } else { log(0, 0, "Initializing group"); if (sync_mode) { log0(0, 0, "- Connect -"); } } rval = 1; packet = calloc(mtu, 1); decrypted = calloc(mtu, 1); if ((packet == NULL) || (decrypted == NULL)) { syserror(0, 0, "calloc failed!"); exit(1); } header = (struct uftp_h *)packet; endtime = time(NULL) + announce_time; announce = (finfo->file_id == 0); regconf = (announce && (keytype == KEY_NONE)); keyinfo = (announce && (keytype != KEY_NONE)); fileinfo = (finfo->file_id != 0); open = (destcount == 0); for (i = 0; i < destcount; i++) { // At start of group, initialize all clients/proxies to DEST_MUTE. // At start of file, initialize proxies to DEST_ACTIVE (since they // don't respond directly to a FILEINFO) and clients to DEST_REGISTERED. if (announce) { destlist[i].status = DEST_MUTE; } else if (!client_error(i)) { if (destlist[i].clientcnt != -1) { destlist[i].status = DEST_ACTIVE; } else { destlist[i].status = DEST_REGISTERED; } } } timeout.tv_sec = announce_int / 1000; timeout.tv_usec = (announce_int % 1000) * 1000; resend = 1; attempt = 1; last_pass = 0; regdone = 0; while (time(NULL) < endtime) { // On the initial pass, or when the announce timeout trips, // send any necessary messages. if (resend) { if (keyinfo && !send_keyinfo(finfo, attempt)) { continue; } if (announce && !send_regconf(finfo, attempt, regconf)) { continue; } if (fileinfo && !send_fileinfo(finfo, attempt)) { continue; } if (announce && !send_announce(finfo, attempt, open)) { continue; } resend = 0; } // TODO: Currently, the interval between sends is really an inactivity // timer, not the actual time between sends. We might want to change // it to that, and perhaps add an extra "overage" timer in case we're // still processing responses when we're due to resend, that way we'll // always wait some minimum amount of time. if ((rcv_status = read_packet(sock, &receiver, packet, &len, mtu, &timeout)) == -1) { continue; } else if (rcv_status == 0) { attempt++; resend = 1; if (last_pass) break; continue; } if (!validate_packet(packet, len, finfo)) { continue; } if (!handle_announce_phase(packet, decrypted, &receiver, finfo, announce, open, regconf)) { continue; } if (!open) { for (i = 0, gotall = 1, allreg = 1; (i < destcount) && (gotall || allreg); i++) { if (announce) { gotall = gotall && ((destlist[i].status == DEST_ACTIVE) || (destlist[i].status == DEST_ABORT)); allreg = allreg && ((destlist[i].status == DEST_ACTIVE) || (destlist[i].status == DEST_REGISTERED) || (destlist[i].status == DEST_ABORT)); } else { gotall = gotall && ((destlist[i].status == DEST_ACTIVE) || (destlist[i].status == DEST_DONE) || (client_error(i))); } } if (gotall) { // Break out right away if this is a file registration. // For group registration, do one last wait, even if // encryption is enabled since we can still send a // REG_CONF for a client behind a proxy. // Change the wait interval to the client's register_int * 1.5 // to allow for late registers. // Be careful not to overrun the phase timeout! if (finfo->file_id != 0) break; timeout.tv_sec = (int)(register_int / 1000 * 1.5); timeout.tv_usec = (int)((register_int % 1000) * 1000 * 1.5); if (timeout.tv_sec > endtime) { #ifdef WINDOWS timeout.tv_sec = (long)endtime; #else timeout.tv_sec = endtime; #endif timeout.tv_usec = 0; } if (!last_pass) { log(0, 0, "Late registers:"); } last_pass = 1; send_regconf(finfo, attempt + 1, regconf); } else if (announce && allreg && !regdone) { // All have registered, so don't wait to send the next message resend = 1; regdone = 1; } } } for (i = 0, gotone = 0, anyerror = 0; i < destcount; i++) { gotone = gotone || (((destlist[i].status == DEST_ACTIVE) || (destlist[i].status == DEST_DONE)) && (destlist[i].clientcnt == -1)); if (destlist[i].status == DEST_REGISTERED) { log1(0, 0, "Couldn't get INFO_ACK from %s", destlist[i].name); destlist[i].status = DEST_LOST; anyerror = 1; } if ((destlist[i].status == DEST_MUTE) || (destlist[i].status == DEST_ABORT)) { anyerror = 1; } } if (anyerror && quit_on_error) { log0(0, 0, "Aboring all clients"); send_abort(finfo, "A client dropped out, aborting all", &receive_dest, NULL, (keytype != KEY_NONE), 0); for (i = 0; i < destcount; i++) { if (destlist[i].status == DEST_ACTIVE) { destlist[i].status = DEST_ABORT; } } rval = 0; } if (!gotone) { log0(0, 0, "Announce timed out"); rval = 0; } if (open) { send_regconf(finfo, attempt, regconf); } if ((finfo->file_id == 0) && sync_mode) { for (i = 0; i < destcount; i++) { if (destlist[i].status == DEST_ACTIVE) { log0(0, 0, "CONNECT;success;%s", destlist[i].name); } else { log0(0, 0, "CONNECT;failed;%s", destlist[i].name); } } log0(0, 0, "- Transfer -"); } free(packet); free(decrypted); return rval; }