| | 828 | } |
|---|
| | 829 | |
|---|
| | 830 | static void add_bin_header(conn *c, int err, int body_len) { |
|---|
| | 831 | int i=0; |
|---|
| | 832 | uint32_t res_header[BIN_PKT_HDR_WORDS]; |
|---|
| | 833 | |
|---|
| | 834 | assert(c); |
|---|
| | 835 | assert(body_len >= 0); |
|---|
| | 836 | |
|---|
| | 837 | c->msgcurr = 0; |
|---|
| | 838 | c->msgused = 0; |
|---|
| | 839 | c->iovused = 0; |
|---|
| | 840 | if (add_msghdr(c) != 0) { |
|---|
| | 841 | /* XXX: out_string is inappropriate here */ |
|---|
| | 842 | out_string(c, "SERVER_ERROR out of memory"); |
|---|
| | 843 | return; |
|---|
| | 844 | } |
|---|
| | 845 | |
|---|
| | 846 | res_header[0] = BIN_RES_MAGIC << 24; |
|---|
| | 847 | res_header[0] |= ((0xff & c->cmd) << 16); |
|---|
| | 848 | res_header[0] |= (err << 8); |
|---|
| | 849 | |
|---|
| | 850 | res_header[1] = c->opaque; |
|---|
| | 851 | res_header[2] = body_len; |
|---|
| | 852 | |
|---|
| | 853 | if(settings.verbose > 1) { |
|---|
| | 854 | fprintf(stderr, "Writing bin response: %08x %08x %08x\n", |
|---|
| | 855 | res_header[0], res_header[1], res_header[2]); |
|---|
| | 856 | } |
|---|
| | 857 | |
|---|
| | 858 | for(i=0; i<BIN_PKT_HDR_WORDS; i++) { |
|---|
| | 859 | res_header[i] = htonl(res_header[i]); |
|---|
| | 860 | } |
|---|
| | 861 | |
|---|
| | 862 | assert(c->wsize >= MIN_BIN_PKT_LENGTH); |
|---|
| | 863 | memcpy(c->wbuf, &res_header, MIN_BIN_PKT_LENGTH); |
|---|
| | 864 | add_iov(c, c->wbuf, MIN_BIN_PKT_LENGTH); |
|---|
| | 865 | } |
|---|
| | 866 | |
|---|
| | 867 | static void write_bin_error(conn *c, int err, int swallow) { |
|---|
| | 868 | char *errstr="Unknown error"; |
|---|
| | 869 | switch(err) { |
|---|
| | 870 | case ERR_UNKNOWN_CMD: |
|---|
| | 871 | errstr="Unknown command"; |
|---|
| | 872 | break; |
|---|
| | 873 | case ERR_NOT_FOUND: |
|---|
| | 874 | errstr="Not found"; |
|---|
| | 875 | break; |
|---|
| | 876 | case ERR_INVALID_ARGUMENTS: |
|---|
| | 877 | errstr="Invalid arguments"; |
|---|
| | 878 | break; |
|---|
| | 879 | case ERR_EXISTS: |
|---|
| | 880 | errstr="Data exists for key."; |
|---|
| | 881 | break; |
|---|
| | 882 | case ERR_TOO_LARGE: |
|---|
| | 883 | errstr="Too large."; |
|---|
| | 884 | break; |
|---|
| | 885 | case ERR_NOT_STORED: |
|---|
| | 886 | errstr="Not stored."; |
|---|
| | 887 | break; |
|---|
| | 888 | default: |
|---|
| | 889 | errstr="UNHANDLED ERROR"; |
|---|
| | 890 | fprintf(stderr, "UNHANDLED ERROR: %d\n", err); |
|---|
| | 891 | } |
|---|
| | 892 | if(settings.verbose > 0) { |
|---|
| | 893 | fprintf(stderr, "Writing an error: %s\n", errstr); |
|---|
| | 894 | } |
|---|
| | 895 | add_bin_header(c, err, strlen(errstr)); |
|---|
| | 896 | add_iov(c, errstr, strlen(errstr)); |
|---|
| | 897 | |
|---|
| | 898 | conn_set_state(c, conn_mwrite); |
|---|
| | 899 | if(swallow > 0) { |
|---|
| | 900 | c->sbytes=swallow; |
|---|
| | 901 | c->write_and_go = conn_swallow; |
|---|
| | 902 | } else { |
|---|
| | 903 | c->write_and_go = conn_bin_init; |
|---|
| | 904 | } |
|---|
| | 905 | } |
|---|
| | 906 | |
|---|
| | 907 | /* Form and send a response to a command over the binary protocol */ |
|---|
| | 908 | static void write_bin_response(conn *c, void *d, int dlen) { |
|---|
| | 909 | add_bin_header(c, 0, dlen); |
|---|
| | 910 | if(dlen > 0) { |
|---|
| | 911 | add_iov(c, d, dlen); |
|---|
| | 912 | } |
|---|
| | 913 | conn_set_state(c, conn_mwrite); |
|---|
| | 914 | c->write_and_go = conn_bin_init; |
|---|
| | 915 | } |
|---|
| | 916 | |
|---|
| | 917 | /* Byte swap a 64-bit number */ |
|---|
| | 918 | static int64_t swap64(int64_t in) { |
|---|
| | 919 | #ifdef ENDIAN_LITTLE |
|---|
| | 920 | /* Little endian, flip the bytes around until someone makes a faster/better |
|---|
| | 921 | * way to do this. */ |
|---|
| | 922 | int64_t rv=0; |
|---|
| | 923 | int i=0; |
|---|
| | 924 | for(i=0; i<8; i++) { |
|---|
| | 925 | rv = (rv << 8) | (in & 0xff); |
|---|
| | 926 | in >>= 8; |
|---|
| | 927 | } |
|---|
| | 928 | return rv; |
|---|
| | 929 | #else |
|---|
| | 930 | /* big-endian machines don't need byte swapping */ |
|---|
| | 931 | return in; |
|---|
| | 932 | #endif |
|---|
| | 933 | } |
|---|
| | 934 | |
|---|
| | 935 | static void complete_incr_bin(conn *c) { |
|---|
| | 936 | item *it; |
|---|
| | 937 | int64_t delta; |
|---|
| | 938 | uint64_t initial; |
|---|
| | 939 | int32_t exptime; |
|---|
| | 940 | char *key; |
|---|
| | 941 | size_t nkey; |
|---|
| | 942 | int i,res; |
|---|
| | 943 | char *responseBuf = c->wbuf + BIN_INCR_HDR_LEN; |
|---|
| | 944 | |
|---|
| | 945 | assert(c != NULL); |
|---|
| | 946 | |
|---|
| | 947 | key=c->rbuf + BIN_INCR_HDR_LEN; |
|---|
| | 948 | nkey=c->keylen; |
|---|
| | 949 | key[nkey]=0x00; |
|---|
| | 950 | |
|---|
| | 951 | delta = swap64(*((int64_t*)(c->rbuf))); |
|---|
| | 952 | initial = (uint64_t)swap64(*((int64_t*)(c->rbuf + 8))); |
|---|
| | 953 | exptime = ntohl(*((int*)(c->rbuf + 16))); |
|---|
| | 954 | |
|---|
| | 955 | if(settings.verbose) { |
|---|
| | 956 | fprintf(stderr, "incr "); |
|---|
| | 957 | for(i=0; i<nkey; i++) { |
|---|
| | 958 | fprintf(stderr, "%c", key[i]); |
|---|
| | 959 | } |
|---|
| | 960 | fprintf(stderr, " %lld, %llu, %d\n", delta, initial, exptime); |
|---|
| | 961 | } |
|---|
| | 962 | |
|---|
| | 963 | /* XXX: Not sure what to do with these yet |
|---|
| | 964 | if (settings.managed) { |
|---|
| | 965 | int bucket = c->bucket; |
|---|
| | 966 | if (bucket == -1) { |
|---|
| | 967 | out_string(c, "CLIENT_ERROR no BG data in managed mode"); |
|---|
| | 968 | return; |
|---|
| | 969 | } |
|---|
| | 970 | c->bucket = -1; |
|---|
| | 971 | if (buckets[bucket] != c->gen) { |
|---|
| | 972 | out_string(c, "ERROR_NOT_OWNER"); |
|---|
| | 973 | return; |
|---|
| | 974 | } |
|---|
| | 975 | } |
|---|
| | 976 | */ |
|---|
| | 977 | |
|---|
| | 978 | it = item_get(key, nkey); |
|---|
| | 979 | if (it) { |
|---|
| | 980 | /* Weird magic in add_delta forces me to pad here */ |
|---|
| | 981 | memset(responseBuf, ' ', 32); |
|---|
| | 982 | responseBuf[32]=0x00; |
|---|
| | 983 | add_delta(it, true, delta, responseBuf); |
|---|
| | 984 | res = strlen(responseBuf); |
|---|
| | 985 | |
|---|
| | 986 | assert(res > 0); |
|---|
| | 987 | write_bin_response(c, responseBuf, res); |
|---|
| | 988 | item_remove(it); /* release our reference */ |
|---|
| | 989 | } else { |
|---|
| | 990 | if(exptime >= 0) { |
|---|
| | 991 | /* Save some room for the response */ |
|---|
| | 992 | assert(c->wsize > BIN_INCR_HDR_LEN + 32); |
|---|
| | 993 | snprintf(responseBuf, BIN_INCR_HDR_LEN + 32, "%llu", initial); |
|---|
| | 994 | |
|---|
| | 995 | res = strlen(responseBuf); |
|---|
| | 996 | it = item_alloc(key, nkey, 0, realtime(exptime), res + 2); |
|---|
| | 997 | |
|---|
| | 998 | memcpy(ITEM_data(it), responseBuf, res); |
|---|
| | 999 | |
|---|
| | 1000 | if(store_item(it, NREAD_SET)) { |
|---|
| | 1001 | write_bin_response(c, responseBuf, res); |
|---|
| | 1002 | } else { |
|---|
| | 1003 | write_bin_error(c, ERR_NOT_STORED, 0); |
|---|
| | 1004 | } |
|---|
| | 1005 | item_remove(it); /* release our reference */ |
|---|
| | 1006 | } else { |
|---|
| | 1007 | write_bin_error(c, ERR_NOT_FOUND, 0); |
|---|
| | 1008 | } |
|---|
| | 1009 | } |
|---|
| | 1010 | } |
|---|
| | 1011 | |
|---|
| | 1012 | static void complete_update_bin(conn *c) { |
|---|
| | 1013 | assert(c != NULL); |
|---|
| | 1014 | |
|---|
| | 1015 | item *it = c->item; |
|---|
| | 1016 | |
|---|
| | 1017 | STATS_LOCK(); |
|---|
| | 1018 | stats.set_cmds++; |
|---|
| | 1019 | STATS_UNLOCK(); |
|---|
| | 1020 | |
|---|
| | 1021 | /* We don't actually receive the trailing two characters in the bin |
|---|
| | 1022 | * protocol, so we're going to just set them here */ |
|---|
| | 1023 | *(ITEM_data(it) + it->nbytes - 2) = '\r'; |
|---|
| | 1024 | *(ITEM_data(it) + it->nbytes - 1) = '\n'; |
|---|
| | 1025 | |
|---|
| | 1026 | if (store_item(it, c->item_comm)) { |
|---|
| | 1027 | /* Stored */ |
|---|
| | 1028 | write_bin_response(c, NULL, 0); |
|---|
| | 1029 | } else { |
|---|
| | 1030 | /* not Stored */ |
|---|
| | 1031 | int eno=-1; |
|---|
| | 1032 | if(c->item_comm == NREAD_ADD) { |
|---|
| | 1033 | eno=ERR_EXISTS; |
|---|
| | 1034 | } else if(c->item_comm == NREAD_REPLACE) { |
|---|
| | 1035 | eno=ERR_NOT_FOUND; |
|---|
| | 1036 | } else { |
|---|
| | 1037 | eno=ERR_NOT_STORED; |
|---|
| | 1038 | } |
|---|
| | 1039 | write_bin_error(c, eno, 0); |
|---|
| | 1040 | } |
|---|
| | 1041 | |
|---|
| | 1042 | item_remove(c->item); /* release the c->item reference */ |
|---|
| | 1043 | c->item = 0; |
|---|
| | 1044 | } |
|---|
| | 1045 | |
|---|
| | 1046 | static void process_bin_get(conn *c) { |
|---|
| | 1047 | item *it; |
|---|
| | 1048 | |
|---|
| | 1049 | it = item_get(c->rbuf, c->keylen); |
|---|
| | 1050 | if (it) { |
|---|
| | 1051 | int *flags; |
|---|
| | 1052 | |
|---|
| | 1053 | assert(c->rsize >= MIN_BIN_PKT_LENGTH + 4); |
|---|
| | 1054 | |
|---|
| | 1055 | /* This is a bit of magic. I'm using wbuf as the header, so I'll place |
|---|
| | 1056 | this is int in far enough to cover the header */ |
|---|
| | 1057 | flags=(int*)(c->wbuf + MIN_BIN_PKT_LENGTH); |
|---|
| | 1058 | *flags=htonl(strtoul(ITEM_suffix(it), NULL, 10)); |
|---|
| | 1059 | |
|---|
| | 1060 | /* the length has two unnecessary bytes, and then we write four more */ |
|---|
| | 1061 | add_bin_header(c, 0, it->nbytes - 2 + 4); |
|---|
| | 1062 | /* Flags and value */ |
|---|
| | 1063 | add_iov(c, flags, 4); |
|---|
| | 1064 | /* bytes minus the CRLF */ |
|---|
| | 1065 | add_iov(c, ITEM_data(it), it->nbytes - 2); |
|---|
| | 1066 | conn_set_state(c, conn_mwrite); |
|---|
| | 1067 | } else { |
|---|
| | 1068 | if(c->cmd == CMD_GETQ) { |
|---|
| | 1069 | conn_set_state(c, conn_bin_init); |
|---|
| | 1070 | } else { |
|---|
| | 1071 | write_bin_error(c, ERR_NOT_FOUND, 0); |
|---|
| | 1072 | } |
|---|
| | 1073 | } |
|---|
| | 1074 | } |
|---|
| | 1075 | |
|---|
| | 1076 | static void bin_read_key(conn *c, int next_substate, int extra) { |
|---|
| | 1077 | assert(c); |
|---|
| | 1078 | c->substate = next_substate; |
|---|
| | 1079 | c->rlbytes = c->keylen + extra; |
|---|
| | 1080 | assert(c->rsize >= c->rlbytes); |
|---|
| | 1081 | c->ritem = c->rbuf; |
|---|
| | 1082 | conn_set_state(c, conn_nread); |
|---|
| | 1083 | } |
|---|
| | 1084 | |
|---|
| | 1085 | static void dispatch_bin_command(conn *c) { |
|---|
| | 1086 | time_t exptime = 0; |
|---|
| | 1087 | switch(c->cmd) { |
|---|
| | 1088 | case CMD_VERSION: |
|---|
| | 1089 | write_bin_response(c, VERSION, strlen(VERSION)); |
|---|
| | 1090 | break; |
|---|
| | 1091 | case CMD_FLUSH: |
|---|
| | 1092 | set_current_time(); |
|---|
| | 1093 | |
|---|
| | 1094 | settings.oldest_live = current_time - 1; |
|---|
| | 1095 | item_flush_expired(); |
|---|
| | 1096 | write_bin_response(c, NULL, 0); |
|---|
| | 1097 | break; |
|---|
| | 1098 | case CMD_NOOP: |
|---|
| | 1099 | write_bin_response(c, NULL, 0); |
|---|
| | 1100 | break; |
|---|
| | 1101 | case CMD_SET: |
|---|
| | 1102 | /* Fallthrough */ |
|---|
| | 1103 | case CMD_ADD: |
|---|
| | 1104 | /* Fallthrough */ |
|---|
| | 1105 | case CMD_REPLACE: |
|---|
| | 1106 | bin_read_key(c, bin_reading_set_header, BIN_SET_HDR_LEN); |
|---|
| | 1107 | break; |
|---|
| | 1108 | case CMD_GETQ: |
|---|
| | 1109 | case CMD_GET: |
|---|
| | 1110 | bin_read_key(c, bin_reading_get_key, 0); |
|---|
| | 1111 | break; |
|---|
| | 1112 | case CMD_DELETE: |
|---|
| | 1113 | bin_read_key(c, bin_reading_del_header, BIN_DEL_HDR_LEN); |
|---|
| | 1114 | break; |
|---|
| | 1115 | case CMD_INCR: |
|---|
| | 1116 | bin_read_key(c, bin_reading_incr_header, BIN_INCR_HDR_LEN); |
|---|
| | 1117 | break; |
|---|
| | 1118 | default: |
|---|
| | 1119 | write_bin_error(c, ERR_UNKNOWN_CMD, c->bin_header[2]); |
|---|
| | 1120 | } |
|---|
| | 1121 | } |
|---|
| | 1122 | |
|---|
| | 1123 | static void process_bin_update(conn *c) { |
|---|
| | 1124 | char *key; |
|---|
| | 1125 | int nkey; |
|---|
| | 1126 | int vlen; |
|---|
| | 1127 | int flags; |
|---|
| | 1128 | int exptime; |
|---|
| | 1129 | item *it; |
|---|
| | 1130 | int comm; |
|---|
| | 1131 | |
|---|
| | 1132 | assert(c != NULL); |
|---|
| | 1133 | |
|---|
| | 1134 | key=c->rbuf + BIN_SET_HDR_LEN; |
|---|
| | 1135 | nkey=c->keylen; |
|---|
| | 1136 | key[nkey]=0x00; |
|---|
| | 1137 | |
|---|
| | 1138 | flags = ntohl(*((int*)(c->rbuf))); |
|---|
| | 1139 | exptime = ntohl(*((int*)(c->rbuf + 4))); |
|---|
| | 1140 | vlen = c->bin_header[2] - (nkey + BIN_SET_HDR_LEN); |
|---|
| | 1141 | |
|---|
| | 1142 | if (settings.detail_enabled) { |
|---|
| | 1143 | stats_prefix_record_set(key); |
|---|
| | 1144 | } |
|---|
| | 1145 | |
|---|
| | 1146 | /* Not sure what to do with this. |
|---|
| | 1147 | if (settings.managed) { |
|---|
| | 1148 | int bucket = c->bucket; |
|---|
| | 1149 | if (bucket == -1) { |
|---|
| | 1150 | out_string(c, "CLIENT_ERROR no BG data in managed mode"); |
|---|
| | 1151 | return; |
|---|
| | 1152 | } |
|---|
| | 1153 | c->bucket = -1; |
|---|
| | 1154 | if (buckets[bucket] != c->gen) { |
|---|
| | 1155 | out_string(c, "ERROR_NOT_OWNER"); |
|---|
| | 1156 | return; |
|---|
| | 1157 | } |
|---|
| | 1158 | } |
|---|
| | 1159 | */ |
|---|
| | 1160 | |
|---|
| | 1161 | it = item_alloc(key, nkey, flags, realtime(exptime), vlen+2); |
|---|
| | 1162 | |
|---|
| | 1163 | if (it == 0) { |
|---|
| | 1164 | if (! item_size_ok(nkey, flags, vlen + 2)) { |
|---|
| | 1165 | write_bin_error(c, ERR_TOO_LARGE, vlen); |
|---|
| | 1166 | } else { |
|---|
| | 1167 | write_bin_error(c, ERR_OUT_OF_MEMORY, vlen); |
|---|
| | 1168 | } |
|---|
| | 1169 | /* swallow the data line */ |
|---|
| | 1170 | c->write_and_go = conn_swallow; |
|---|
| | 1171 | return; |
|---|
| | 1172 | } |
|---|
| | 1173 | |
|---|
| | 1174 | switch(c->cmd) { |
|---|
| | 1175 | case CMD_ADD: |
|---|
| | 1176 | c->item_comm = NREAD_ADD; |
|---|
| | 1177 | break; |
|---|
| | 1178 | case CMD_SET: |
|---|
| | 1179 | c->item_comm = NREAD_SET; |
|---|
| | 1180 | break; |
|---|
| | 1181 | case CMD_REPLACE: |
|---|
| | 1182 | c->item_comm = NREAD_REPLACE; |
|---|
| | 1183 | break; |
|---|
| | 1184 | default: |
|---|
| | 1185 | assert(0); |
|---|
| | 1186 | } |
|---|
| | 1187 | |
|---|
| | 1188 | c->item = it; |
|---|
| | 1189 | c->ritem = ITEM_data(it); |
|---|
| | 1190 | c->rlbytes = vlen; |
|---|
| | 1191 | conn_set_state(c, conn_nread); |
|---|
| | 1192 | c->substate = bin_read_set_value; |
|---|
| | 1193 | } |
|---|
| | 1194 | |
|---|
| | 1195 | static void process_bin_delete(conn *c) { |
|---|
| | 1196 | char *key; |
|---|
| | 1197 | size_t nkey; |
|---|
| | 1198 | item *it; |
|---|
| | 1199 | time_t exptime = 0; |
|---|
| | 1200 | |
|---|
| | 1201 | assert(c != NULL); |
|---|
| | 1202 | |
|---|
| | 1203 | /* XXX: I don't know what to do with this yet |
|---|
| | 1204 | if (settings.managed) { |
|---|
| | 1205 | int bucket = c->bucket; |
|---|
| | 1206 | if (bucket == -1) { |
|---|
| | 1207 | out_string(c, "CLIENT_ERROR no BG data in managed mode"); |
|---|
| | 1208 | return; |
|---|
| | 1209 | } |
|---|
| | 1210 | c->bucket = -1; |
|---|
| | 1211 | if (buckets[bucket] != c->gen) { |
|---|
| | 1212 | out_string(c, "ERROR_NOT_OWNER"); |
|---|
| | 1213 | return; |
|---|
| | 1214 | } |
|---|
| | 1215 | } |
|---|
| | 1216 | */ |
|---|
| | 1217 | |
|---|
| | 1218 | exptime = ntohl(*((int*)(c->rbuf))); |
|---|
| | 1219 | key = c->rbuf + 4; |
|---|
| | 1220 | nkey = c->keylen; |
|---|
| | 1221 | key[nkey]=0x00; |
|---|
| | 1222 | |
|---|
| | 1223 | if(settings.verbose) { |
|---|
| | 1224 | fprintf(stderr, "Deleting %s with a timeout of %d\n", key, exptime); |
|---|
| | 1225 | } |
|---|
| | 1226 | |
|---|
| | 1227 | if (settings.detail_enabled) { |
|---|
| | 1228 | stats_prefix_record_delete(key); |
|---|
| | 1229 | } |
|---|
| | 1230 | |
|---|
| | 1231 | it = item_get(key, nkey); |
|---|
| | 1232 | if (it) { |
|---|
| | 1233 | if (exptime == 0) { |
|---|
| | 1234 | item_unlink(it); |
|---|
| | 1235 | item_remove(it); /* release our reference */ |
|---|
| | 1236 | write_bin_response(c, NULL, 0); |
|---|
| | 1237 | } else { |
|---|
| | 1238 | /* XXX: This is really lame, but defer_delete returns a string */ |
|---|
| | 1239 | char *res=defer_delete(it, exptime); |
|---|
| | 1240 | if(res[0] == 'D') { |
|---|
| | 1241 | write_bin_response(c, NULL, 0); |
|---|
| | 1242 | } else { |
|---|
| | 1243 | write_bin_error(c, ERR_OUT_OF_MEMORY, 0); |
|---|
| | 1244 | } |
|---|
| | 1245 | } |
|---|
| | 1246 | } else { |
|---|
| | 1247 | write_bin_error(c, ERR_NOT_FOUND, 0); |
|---|
| | 1248 | } |
|---|
| | 1249 | } |
|---|
| | 1250 | |
|---|
| | 1251 | static void complete_nread_binary(conn *c) { |
|---|
| | 1252 | assert(c != NULL); |
|---|
| | 1253 | |
|---|
| | 1254 | if(c->cmd < 0) { |
|---|
| | 1255 | /* No command defined. Figure out what they're trying to say. */ |
|---|
| | 1256 | int i=0; |
|---|
| | 1257 | /* I did a bit of hard-coding around the packet sizes */ |
|---|
| | 1258 | assert(BIN_PKT_HDR_WORDS == 3); |
|---|
| | 1259 | for(i=0; i<BIN_PKT_HDR_WORDS; i++) { |
|---|
| | 1260 | c->bin_header[i] = ntohl(c->bin_header[i]); |
|---|
| | 1261 | } |
|---|
| | 1262 | if(settings.verbose) { |
|---|
| | 1263 | fprintf(stderr, "Read binary protocol data: %08x %08x %08x\n", |
|---|
| | 1264 | c->bin_header[0], c->bin_header[1], c->bin_header[2]); |
|---|
| | 1265 | } |
|---|
| | 1266 | if((c->bin_header[0] >> 24) != BIN_REQ_MAGIC) { |
|---|
| | 1267 | if(settings.verbose) { |
|---|
| | 1268 | fprintf(stderr, "Invalid magic: %x\n", c->bin_header[0] >> 24); |
|---|
| | 1269 | } |
|---|
| | 1270 | conn_set_state(c, conn_closing); |
|---|
| | 1271 | return; |
|---|
| | 1272 | } |
|---|
| | 1273 | |
|---|
| | 1274 | c->msgcurr = 0; |
|---|
| | 1275 | c->msgused = 0; |
|---|
| | 1276 | c->iovused = 0; |
|---|
| | 1277 | if (add_msghdr(c) != 0) { |
|---|
| | 1278 | out_string(c, "SERVER_ERROR out of memory"); |
|---|
| | 1279 | return; |
|---|
| | 1280 | } |
|---|
| | 1281 | |
|---|
| | 1282 | c->cmd = (c->bin_header[0] >> 16) & 0xff; |
|---|
| | 1283 | c->keylen = (c->bin_header[0] >> 8) & 0xff; |
|---|
| | 1284 | c->opaque = c->bin_header[1]; |
|---|
| | 1285 | if(settings.verbose > 1) { |
|---|
| | 1286 | fprintf(stderr, |
|---|
| | 1287 | "Command: %d, opaque=%08x, keylen=%d, total_len=%d\n", c->cmd, |
|---|
| | 1288 | c->opaque, c->keylen, c->bin_header[2]); |
|---|
| | 1289 | } |
|---|
| | 1290 | dispatch_bin_command(c); |
|---|
| | 1291 | } else { |
|---|
| | 1292 | switch(c->substate) { |
|---|
| | 1293 | case bin_reading_set_header: |
|---|
| | 1294 | process_bin_update(c); |
|---|
| | 1295 | break; |
|---|
| | 1296 | case bin_read_set_value: |
|---|
| | 1297 | complete_update_bin(c); |
|---|
| | 1298 | break; |
|---|
| | 1299 | case bin_reading_get_key: |
|---|
| | 1300 | process_bin_get(c); |
|---|
| | 1301 | break; |
|---|
| | 1302 | case bin_reading_del_header: |
|---|
| | 1303 | process_bin_delete(c); |
|---|
| | 1304 | break; |
|---|
| | 1305 | case bin_reading_incr_header: |
|---|
| | 1306 | complete_incr_bin(c); |
|---|
| | 1307 | break; |
|---|
| | 1308 | default: |
|---|
| | 1309 | fprintf(stderr, "Not handling substate %d\n", c->substate); |
|---|
| | 1310 | assert(0); |
|---|
| | 1311 | } |
|---|
| | 1312 | } |
|---|
| | 1313 | } |
|---|
| | 1314 | |
|---|
| | 1315 | static void complete_nread(conn *c) { |
|---|
| | 1316 | assert(c != NULL); |
|---|
| | 1317 | |
|---|
| | 1318 | if(c->protocol == ascii_prot) { |
|---|
| | 1319 | complete_nread_ascii(c); |
|---|
| | 1320 | } else if(c->protocol == binary_prot) { |
|---|
| | 1321 | complete_nread_binary(c); |
|---|
| | 1322 | } else { |
|---|
| | 1323 | assert(0); /* XXX: Invalid case. Should probably do more here. */ |
|---|
| | 1324 | } |
|---|